【脏读】

对于对象同步和异步的方法,我们在设计程序的时候,一定要考虑问题的整体,不然会出现不一致的错误,最经典的错误的就是脏读(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深入的更多相关文章

随机推荐

  1. CentOS中源码编译安装Nginx

    1.从官网通过wget命令将Nginx源码包下载到Linux上 ​ Nginx下载页面:http://nginx.org/en/download.html 2.在Linux上安装需要依赖的环境 yum ...

  2. java 的在线下载文件 .pdf

    java  的在线下载文件  .pdf 1.下载资源的本地位置 2.设置响应头 3.下载代码 1 PeriodicalResource periodicalResource = periodicalR ...

  3. 移动端适配1px问题

    (function(document) { var dcl = document.documentElement, wh; var scale = 1/window.devicePixelRatio; ...

  4. 并排的两个div之间会有空隙

    两个并排的DIV会有如下图所示的空隙 是因为 代码中 两个DIV之前有个 ’回车‘ 这么写就OK了 可是为什么会有这种问题呢,是因为浏览器将 空格.回车.tab键等字符都当做一个空格处理,所以当你回车 ...

  5. vue 中引用 百度地图

    1.在 http://lbsyun.baidu.com/ 申请 秘钥 2.在index.html文件中引入 <script src="http://api.map.baidu.com/ ...

  6. 挑战程序设计竞赛 P131 区间DP

    书上好多题没补 PS.整个DP是根据Q来划分的,dalao的代码就是不一样啊 #include<bits/stdc++.h> #define rep(i,j,k) for(int i=j; ...

  7. 本地安全策略命令行secedit设置本地账户安全策略

    我们日常运行的控制台程序secpol.msc里面的内容,实质可以通过命令行完成,下面演示通过secedit命令来设置本地账号密码策略,启用密码复杂性和强制长度至少8位操作办法. ==> 新建文本 ...

  8. 剑指offer5.1——O(n)的复杂度合并两个有序数组

    #include"iostream" #include"stdio.h" using namespace std; int* ArrayMerge(int *a ...

  9. js动态给textarea赋值

    document.getElementById("new_analysed_news").value=datas.weatherContent;

  10. linux 期中架构之 nginx 安装与排错

    1, 安装 nginx 所需要的pcre库 即:perl 兼容正则表达式 yum install pcre pcre-devel -y rpm -qa pcre pcre-devel 检查是否安装好p ...