Java并发中的可见性和原子性(下篇)

68 阅读1分钟

3、使用Atomicxxxx保证原子性:

public class Test {

    static AtomicInteger a = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
    	
    	for(int i=0; i<10000; i++) {
    		new Thread(()-> {
    			a.getAndAdd(1);
    		}).start();
    		new Thread(()-> {
    			a.getAndAdd(1);
    		}).start();
    	}		
    	
    	Thread.sleep(1000);	//为了保证不会影响,停一秒再写		
    	System.out.println(a); 		//对a执行读操作
    }

}

可以看到,a++的操作改成了getAndAdd(),读和写是一起执行的,这就不会在读值之后写值之前被其他线程插一杠子。

需要注意的一点是,原子性和可见性并不是相互独立的,保证原子性的前提是保证可见性,那为什么我们没有再用volatile修饰a来保证可见性呢?这就需要去看看AtomicInteger的源码了:

其实它的内部也使用了volatile关键字。

4、使用synchronized同步代码段强制实现原子性和可见性

除了Atomic,也可以使用synchronized同步代码段强制实现原子性。

public class Test {

    static AtomicInteger a = new AtomicInteger(0);
    static int b = 0;

    public static void main(String[] args) throws InterruptedException {
    	
    	for(int i=0; i<10000; i++) {
    		new Thread(()-> {

//				a.getAndAdd(1);
synchronized(Test.class) {
b++;
}
}).start();
new Thread(()-> {
//				a.getAndAdd(1);
synchronized(Test.class) {
b++;
}
}).start();
}

    	Thread.sleep(1000);	//为了保证不会影响,停一秒再写		

//		System.out.println(a); 		//对a执行读操作
System.out.println(b); 		//对b执行读操作
}
}

相比较Atomic,synchronized就更加重量级了。

另外:volatile不具有传染性,用volatile修饰的对象的内部属性不具有可见性,反之用volatile修饰的内部属性也不能保证所在对象的可见性。