在多线程的环境下,如果某个线程首次读取共享变量,则首先到主内存中获取该变量,然后存入工作内存中,以后只需要在工作内存中读取该变量即可。同样如果对该变量执行了修改的操作,则先将新值写入工作内存中,然后再刷新至主内存中。但是什么时候最新的值会被刷新至主内存中是不太确定的,这也就解释了为什么VolatileFoo中的Reader线程始终无法获取到init_value最新的变化。· 使用关键字volatile,当一个变量被volatile关键字修饰时,对于共享资源的读操作会直接在主内存中进行(当然也会缓存到工作内存中,当其他线程对该共享资源进行了修改,则会导致当前线程在工作内存中的共享资源失效,所以必须从主内存中再次获取),对于共享资源的写操作当然是先要修改工作内存,但是修改结束后会立刻将其刷新到主内存中。· 通过synchronized关键字能够保证可见性,synchronized关键字能够保证同一时刻只有一个线程获得锁,然后执行同步方法,并且还会确保在锁释放之前,会将对变量的修改刷新到主内存当中。· 通过JUC提供的显式锁Lock也能够保证可见性,Lock的lock方法能够保证在同一时 刻只有一个线程获得锁然后执行同步方法,并且会确保在锁释放(Lock的unlock方法)之前会将对变量的修改刷新到主内存当中。摘自:《Java高并发编程详解:多线程与架构设计》 — 汪文君关于这本书的东西我写了一些代码,用于理解 echobai/thread,包括自己动手写一个可见锁和读写分离锁等更新一:
public class Task implements Runnable { public boolean flag = true;
@Override public void run() { while (flag) { try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "exit.");
} public static void main(String[] args) throws InterruptedException{ Task task = new Task();
Thread t = new Thread(task, "task");
t.start();
TimeUnit.MILLISECONDS.sleep(10); task.flag = false;
}
}正常结束(连续5次测试都可以退出)taskexit.
Process finished with exit code 0public class Task implements Runnable { public boolean flag = true;
@Override public void run() { while (flag) { /*try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
System.out.println("working...");
}
System.out.println(Thread.currentThread().getName() + "exit.");
} public static void main(String[] args) throws InterruptedException{ Task task = new Task();
Thread t = new Thread(task, "task");
t.start();
TimeUnit.MILLISECONDS.sleep(10); task.flag = false;
}
}也是正常退出(连续测试5次):working...
working...
working...
working...
working...
working...
working...
working...
working...
working...
working...
working...
working...
working...
taskexit.
Process finished with exit code 0不明白,你是哪里有问题,主线程退出时候,主线程写入主内存了就,但是如果主线程不退出,也不加锁,就以一定了更新二:确实是我错了,非常抱歉,再次改下代码,再看结果public class Task implements Runnable { public boolean flag = true;
@Override public void run() { boolean f = flag; while (f) {
f = flag;
}
System.out.println(Thread.currentThread().getName() + "exit.");
} public static void main(String[] args) throws InterruptedException{ Task task = new Task();
Thread t = new Thread(task, "task");
t.start();
TimeUnit.MILLISECONDS.sleep(10); task.flag = false;
}
}