14_synchronized深入
【脏读】
对于对象同步和异步的方法,我们在设计程序的时候,一定要考虑问题的整体,不然会出现不一致的错误,最经典的错误的就是脏读(dirty read)。
【实例代码】
package com.higgin.part4; /**
* 在我们对一个对象的方法加锁的时候,需要考虑业务的整体性。
* 本例子中的setValue或getValue必须同时加上synchronized同步关键字,办证业务的原子性,不然会出现业务错误
*/
public class DirtyRead {
private String username="zhangsan";
private String password=""; public synchronized void setValue(String username,String password){
this.username=username;
try {
Thread.sleep(); //延时2秒
} catch (InterruptedException e) {
e.printStackTrace();
}
this.password=password;
System.out.println("setValue最终结果【 username = "+username+", password = "+password + "】");
} /**
* 加和不加synchronized有区别
*/
public void getValue(){
System.out.println("getValue最终结果【 username = "+username+", password = "+password + "】");
} public static void main(String[] args) throws InterruptedException {
final DirtyRead dr = new DirtyRead(); Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
dr.setValue("lisi", "");
}
});
t1.start(); //t1线程去设置值
Thread.sleep();
dr.getValue(); //相当于main线程去读取值
}
}
【运行结果:不加synchronized】

【运行结果:加上synchronized】

【关于synchronized代码块】
直接使用synchronized声明的方法是在有些情况下是有弊端的,比如A线程调用的同步方法执行一个时间很长的任务,那么B线程就必须等待比较长的时间才能执行,这样的情况下可以使用synchronized代码块去优化代码执行时间,也就是通常所说的减小锁的粒度。
【synchronized代码块加锁:对象锁、类锁、任意对象锁】
package com.higgin.part6;
public class DiffLock {
public void method1(){
synchronized(this){ //对象锁
System.out.println("method1");
}
}
public void method2(){
synchronized(DiffLock.class){ //类锁
System.out.println("method2");
}
}
private Object obj = new Object();
public void method3(){
synchronized(obj){ //任意对象锁
System.out.println("method3");
}
}
}
【关于String类型的锁】
注意不要使用String的常量加锁,容易出现死循环问题。
package com.higgin.part6; /**
* synchronized代码块对字符串的锁,注意String常量池的缓存功能
*/
public class StringLock { public void method() {
//分别使用new String("abc")和"abc"
synchronized ("abc") { //这里是一个String类型的常量锁
try {
while(true){
System.out.println("当前线程 : " + Thread.currentThread().getName() + "开始");
Thread.sleep();
System.out.println("当前线程 : " + Thread.currentThread().getName() + "结束");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
final StringLock stringLock = new StringLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
stringLock.method();
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
stringLock.method();
}
},"t2"); t1.start(); //这里本质上t1、t2抢占的是同一个String锁("abc"),t1一直未释放锁,导致t2无法获得锁执行代码
t2.start();
}
}
【运行结果:使用"abc"常量字符串作为锁,t2线程一直无法执行】

【运行结果:使用new String("abc")非常量字符作为锁,t2和t1竞争执行】

14_synchronized深入的更多相关文章
随机推荐
- Freeman链码
[简介] 链码(又称为freeman码)是用曲线起始点的坐标和边界点方向代码来描述曲线或边界的方法,常被用来在图像处理.计算机图形学.模式识别等领域中表示曲线和区域边界.它是一种边界的编码表示法,用边 ...
- 主机和虚拟机互Ping的问题
主机能ping通虚拟机,虚拟机能ping不通主机. 发现原来是被防火墙阻止了.打开主机防火墙禁止Ping的方式. 在ping不通的电脑上对防火墙进行如下设置:依次单击“防火墙”—“高级设置”—“入站规 ...
- Java实现二维码生成的方法
1.支持QRcode.ZXing 二维码生成.解析: package com.thinkgem.jeesite.test; import com.google.zxing.BarcodeFormat; ...
- JavaWeb学习笔记(三)—— Servlet
一.Servlet概述 1.1 什么是Servlet Servlet是是sun公司提供一套规范(接口),是JavaWeb的三大组件之一(Servlet.Filter.Listener),它属于动态资源 ...
- LightOJ - 1140 统计0的数位 数位DP
注意以下几点: 搜索维度非约束条件的都要记录,否则大概率出错,比如_0 st参数传递和_0的互相影响要分辨清楚 num==-1就要返回0而不是1 #include<iostream> #i ...
- HDU - 2089 数位DP 初步
中文题目,不要62和4 从高位往低位DP,注意有界标志limit的传递 dp2记忆有界情况下的计数结果,据说用处不大 我所参考的入门文章就是半搜索(有界)半记忆(无界)的 进阶指南中提出dfs维度有多 ...
- HDU - 6183 动态开点线段树 || 令人绝望的线段树
一看C才[0,50],肯定要开51棵线段树维护y区间的最小x值啦 是男人就上51棵..等等空间爆几倍了 动态开点!51棵线段树用全局节点变量控制,有点像主席树 清空工作很简单,把51个树根清掉然后回收 ...
- 前端页面 script 事件总结
1. input 失去焦点是触发事件 $("#sn").blur(function(){ alert("sdfasdf"); }); 2. 获取文本框中的 ...
- OJ (Online Judge)使用
这是一种方式,我们还可使用另外一种方式: process.stdin.resume(); process.stdin.setEncoding('ascii'); var input = "& ...
- Android的Intent和IntentFilter应用说明一例
很多人对文档中的Intent和IntentFilter不理解是什么意思,我这里举例解释下. Intent字面意思就是目标,目的.通俗一点,需要达成某些目标,则需要提供一些动作,这些目标的分类,以及达成 ...