单例的双重校验加锁方法创建对象变量为什么要加volatile关键字

package volatiletest;


public class singleTest {


// private static singleTest interest=null;//没有加volatile关键字

/* 使用volatile关键字,volatile的作用,告诉jvm该变量是容易改变的(多个线程可能修改此状态),
使用这个变量的时候,需要从内存中重新读取,修改后要马上对内存中的该变量进行更新。
因为线程之间的联系是经过内存联系起来的。
例如:
A、B两个线程共享一个变量 interest。
     第1种情况(不使用volatile):A/B线程用到interest的时候,会从主存中读取出来或者缓存中(自己的内存空间,
      由于没有加volatile关键字所以这个地方是随机的,除非第一次使用该变量是从主存中读取),
      然后放到【自己】的内存中(每个线程都有自己的内存空间),
  然后对自己内存中的变量进行修改,如果没有加volatile关键字修饰的话,
  该线程对主存中的变量修改后的更新是随机的。
  所以多个线程使用同一个变量的时候,尽量加上volatile,还是要加锁的地方就要加锁,volatile不能替代锁 
  【注】 但是大部分还是修改后马上更新
 
     第2中情况(使用volatile): A/B线程用到interest的时候,会从主存中读取出来(绝对是主存中而不是自己的内存空间),
      然后放到【自己】的内存中(每个线程都有自己的内存空间),
  然后对自己内存中的变量进行修改,修改后马上将主存中的该变量进行更新
  所以多个线程使用同一个变量的时候,尽量加上volatile,还是要加锁的地方就要加锁,volatile不能替代锁 
  因为使用加锁的同时对该变量加上volatile关键字,程序更安全。

*/
private volatile static singleTest interest=null; 

private singleTest(){}

public static singleTest getInsert(){
if(interest==null){
synchronized(singleTest.class){
if(interest==null){
interest = new singleTest();
}
}
}
return interest;
}

}


package volatiletest;

public class mainTest {


public static void main(String[] args) {

// 创建10000个线程的第一种方法
RunTest[] rt = new RunTest[10000];
for(int i=0;i<10000;i++){
rt[i] = new RunTest();
rt[i].start();
}

for(int i=0;i<RunTest.arrlist.size();i++){
if(!RunTest.str.equals(RunTest.arrlist.get(i))){
System.out.println(RunTest.str+"当前线程:"+i);
System.out.println(RunTest.arrlist.get(i));
}
}

// 让主线程休眠500毫秒的,是因为其他线程还没有执行完就执行到了RunTest.count,就会出现不正确的结果(实际上是正确的)
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(RunTest.arrlist.size()); // 集合中地址的个数
System.out.println(rt.length); // 创建线程的个数
System.out.println(RunTest.count); //  run方法执行的次数,也就是多个线程执行了run方法
System.out.println(RunTest.str); // 创建的对象的地址


// 使用线程池创建一千个线程的第二种方法,好处: 能判断所有线程是否全部执行完毕
/* ExecutorService exe = Executors.newFixedThreadPool(10000);    
       for (int i = 0; i < 10000; i++) {    
           exe.execute(new RunTest());    
       }
       
       exe.shutdown();
       while (true) { 
        if (exe.isTerminated()) {
        for(int i=0;i<RunTest.arrlist.size();i++){
        if(!RunTest.str.equals(RunTest.arrlist.get(i))){
        System.out.println(RunTest.str+"当前线程:"+i);
        System.out.println(RunTest.arrlist.get(i));
        }else{
        System.out.println("完美的单例模式");
        }
        }
        System.out.println(""+RunTest.arrlist.size());
        break;
        }
       }*/

}


}


package volatiletest;

import java.util.ArrayList;

public class RunTest extends Thread{

public volatile static ArrayList<String> arrlist = new ArrayList<String>();
public static String str = "";
public volatile static int count=0;

@Override
public void run() {
singleTest s = singleTest.getInsert();
synchronized(RunTest.class){
if(count==0) str = s.toString(); // 拿到第一次创建的对象
arrlist.add(s.toString());
count++;
}
}


}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值