多个线程访问同一份资源,就会产生线程安全问题。
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)的判断
网友评论