一、概念
在java中,每一个线程都会有自己的工作内存区域,在主内存中对共享变量值进行拷贝,形成副本,放在每个线程独自的内存区域。当各自的线程运行时,会在自己的内存区域操作这些变量的值,为了存取一个共享的变量,一个线程通常获锁定并且清除自己的内存工作区,把这些共享变量的值从所有线程共享内存区域中正确的装入到自己的工作内存区域,当线程解锁时,把工作区域的变量值刷新到主内存中的共享变量中。
一个线程可以使用的操作有使用(use),赋值(assign),装载(load),存储(store),锁定(lock),解锁(unlock)
主内存可以执行的操作有:读(read),写(write),锁定(lock),解锁(unlock)
volatile关键字的作用就是强制到主内存(共享内存)里去读取变量,而不是去线程工作区去读,从而实现了多线程间的变量可见,满足线程安全的可见性。当某个线程对共享变量进行更改的时候,线程引擎会强制让引用了共享变量的线程去共享变量中读取值。
volatile不具备原子性,如果要要保证原子性,建议使用automic系列对象(只保证本身原子性,并不保证多次操作的原子性)
/**
* volatile关键字不具备synchronized关键字的原子性(同步)
*
*/
public class VolatileNoAtomic extends Thread{
//private static volatile int count;
private static AtomicInteger count = new AtomicInteger(0);
private static void addCount(){
for (int i = 0; i < 1000; i++) {
//count++ ;
count.incrementAndGet();
}
System.out.println(count);
}
public void run(){
addCount();
}
public static void main(String[] args) {
VolatileNoAtomic[] arr = new VolatileNoAtomic[100];
for (int i = 0; i < 10; i++) {
arr[i] = new VolatileNoAtomic();
}
for (int i = 0; i < 10; i++) {
arr[i].start();
}
}
public class AtomicUse {
private static AtomicInteger count = new AtomicInteger(0);
//多个addAndGet在一个方法内是非原子性的,需要加synchronized进行修饰,保证4个addAndGet整体原子性
/**synchronized*/
public synchronized int multiAdd(){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
count.addAndGet(1);
count.addAndGet(2);
count.addAndGet(3);
count.addAndGet(4); //+10
return count.get();
}
public static void main(String[] args) {
final AtomicUse au = new AtomicUse();
List<Thread> ts = new ArrayList<Thread>();
for (int i = 0; i < 100; i++) {
ts.add(new Thread(new Runnable() {
@Override
public void run() {
System.out.println(au.multiAdd());
}
}));
}
for(Thread t : ts){
t.start();
}
}
}