http://hi.baidu.com/yicun05/blog/item/ce8cf118cec87172dbb4bdd3.html
1:什么是原子操作?
线程执行的最小单位,不能中断。
2:volatile原理是什么?
一般变量,在主存和当线程的临时内存中都一份缓存,为保证数据
统一,需要同步,当同步没有完成时,如果其他线程读取主存上的值就会导致不同步异常。
Volatile就是告诉处理器这个变量是不稳定的,不要在线程的临时内存缓存该数据,直接使用JVM内存的数据,就避免了同步的步骤。
3:对volatile变量数据进行修改(不是重赋值),是否能保证同步?
不能。即使是++,--也不是原子操作,会因为CPU的线程的切换,导致数据不可控。
4:那为什么还要用volatile这种修饰符?
对volatile变量读取,和赋值是可以保证原子性
5:那到底如何解决这样的问题?
第一种:采用同步synchronized解决,这样虽然解决了问题,但是也降低了系统的性能。
第二种:采用原子性数据Atomic变量,这是从JDK1.5开始才存在的针对原子性的解决方案,这种方案也是目前比较好的解决方案了。
6:Atomic的实现基本原理?
* 1)Atomic中的变量是申明为了volatile变量的,这样就保证的变量的存储和读取
* 是一致的,都是来自同一个内存块,
* 2)Atomic对变量的++操作进行了封装,提供了getAndIncrement方法,
* ,并提供了compareAndSet方法,来完成对单个变量的加锁和解锁操作,
* Atomic虽然解决了同步的问题,但是性能上面还是会有所损失,不过影响不大。
7:volatile 是否可以修饰对象实例?为什么对象变量重新赋值也是原子操作?
可以。JVM保证volatile的读操作一定发生在写操作之后,即使没有使用sycnrhonized语块。
因为在栈中,对象变量存储的是一个地址,该地址是指向堆中对象的,所以操作并不负责,
可以认为对一个对象重新赋值是原子操作。
8:为什么在Java中变量赋值中,除了long和double类型的变量外都是原子操作?
由于long和double类型是大于32BIT的,JVM把他们作为2个原子性的32位值来对待,需要进行2次赋值。所以,不是原子操作。
如果,硬件和软件都支持64BIT,则long和double可能就是原子操作。
以下代码起100个线程对AtomicInteger 和volatile 等类型数据,进行1000次的递增,如果是线程安全的最终的值应该是100×1000即100000。否则即表明不是线程安全的。
public class TestAtomic { public static AtomicInteger astom_i = new AtomicInteger(); public static volatile Integer v_integer_i = 0; public static volatile int v_i = 0; public static Integer integer_i = 0; public static int i = 0; public static volatile int endThread = 0; public static void main(String[] args) { new TestAtomic().testAtomic(); } public void testAtomic() { for(int i=0; i<100; i++) { new Thread(new IntegerTestThread()).start(); } try { for(;;) { Thread.sleep(500); if(TestAtomic.endThread == 100) { System.out.println(">>Execute End:"); System.out.println(">>Atomic: \t"+TestAtomic.astom_i); System.out.println(">>VInteger: \t"+TestAtomic.v_integer_i); System.out.println(">>Integer: \t"+TestAtomic.integer_i); System.out.println(">>Source i: \t"+TestAtomic.i); System.out.println(">>Source Vi: \t"+TestAtomic.v_i); break; } } } catch (Exception e) { e.printStackTrace(); } } } class IntegerTestThread implements Runnable { final public static Lock lock=new ReentrantLock(); public void run() { int x = 0; while(x<1000) { TestAtomic.astom_i.incrementAndGet(); TestAtomic.v_integer_i++; TestAtomic.integer_i++; TestAtomic.i++; TestAtomic.v_i++; x++; } //以下其实使用,AtomicInteger就能解决 lock.lock(); ++TestAtomic.endThread; System.out.println("Thread end: "+TestAtomic.endThread); lock.unlock(); } }