14_synchronized深入


【脏读】

对于对象同步和异步的方法,我们在设计程序的时候,一定要考虑问题的整体,不然会出现不一致的错误,最经典的错误的就是脏读(dirty read)。

【实例代码】

package com.higgin.part4;

/**
 * 在我们对一个对象的方法加锁的时候,需要考虑业务的整体性。
 * 本例子中的setValue或getValue必须同时加上synchronized同步关键字,办证业务的原子性,不然会出现业务错误 
 */
public class DirtyRead {
    private String username="zhangsan";
    private String password="123";
    
    public synchronized void setValue(String username,String password){
        this.username=username;
        try {
            Thread.sleep(2000);   //延时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", "456");
            }
        });
        t1.start();   //t1线程去设置值
        Thread.sleep(1000);
        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(1000);        
                    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竞争执行】

优质内容筛选与推荐>>
1、[导入]程序设计与人体条件反射
2、大数据现状分析(2)
3、Expo大作战(二十九)--expo sdk api之registerRootComponent(注册跟组件),ScreenOrientation(屏幕切换),SecureStore,
4、spring基础概念AOP与动态代理理解
5、实训作业1


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn