线程:并发问题

2019-01-16  本文已影响0人  寂静的春天1988

多个线程访问同一份资源,就会产生线程安全问题。
1)可以使用synchronized修饰方法,那么它会阻塞线程,一个线程访问,那么其他线程必须等待!
2)可以使用同步代码块
synchronized (this){

}
同步代码块的形参必须是引用类型,同步代码块容易犯的错:
2.1锁定范围不正确,范围过大,效率低下。范围过小,没有起到线程安全的效果。
2.2锁定资源不正确。

单例模式(恶汉式)

public static void main(String[] args) {
        DemoThread d1=new DemoThread();
        DemoThread d2=new DemoThread();
        d1.start();
        d2.start();
    }
}

class Demo{
    private static Demo demo=null;
    private Demo(){
        
    }
    public static Demo getDemo(){
        if(demo==null){
            try {
                Thread.sleep(10000);//模拟网络延时等
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            demo=new Demo();
        }
        return demo;
    }
}
class DemoThread extends Thread{
    @Override
    public void run() {
        Demo demo = Demo.getDemo();
        System.out.println(demo);
    }
    
}

可以发现由于网络延时等原因,发现上面那段代码在多线程下也有可能创建两个对象
1、可以使用同步方法解决,直接加上synchronized修饰getDemo方法
2、使用同步代码块

public static  Demo getDemo(){
        synchronized(Demo.class){
            if(demo==null){
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                demo=new Demo();
            }
        }
        
        return demo;
    }

上面可以解决,但是发现效率不高,如果对象不为null,那么也要进入同步代码块。可以优化成以下代码

public static  Demo getDemo(){
        if(demo==null){
            synchronized(Demo.class){
                if(demo==null){
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    demo=new Demo();
                }
            }
        }
        return demo;
    }

仔细分析代码可以发现,只需要对象为null时进入同步代码块,所以加了一个if(demo==null)的判断

上一篇下一篇

猜你喜欢

热点阅读