volatile:具有
使用volatile原則:
package zhang.feng.concurrent.atomic;
public class VolatileTest {
private String str="";
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
private void doit(){
new Thread(new Runnable(){
public void run() {
setStr("沒有寫入主存中");
System.out.println("====");
}
},"THREAD_ONE").start();
new Thread(new Runnable(){
public void run() {
String str=getStr();
System.out.println(str);
}
},"THREAD_TWO").start();
}
public static void main(String[] args){
VolatileTest vt=new VolatileTest();
vt.doit();
}
}
上面的例子,如果不使用volatile變量,可能出現的情況是(出現幾率很小),THREAD_ONE線程在setStr()后,THREAD_TWO執行了getStr(),但是由于并沒有將數據寫入主存中,而此時getStr()獲得的數據將是過時數據.
解決的方式,通過lock(開銷比較大),使用volatile變量(如上).
正確使用 volatile 的模式
1.狀態標志
該模式特征:只有一種狀態的轉換.
2.一次性安全發布
該模式的一個必要條件是:被發布的對象必須是線程安全的,或者是有效的不可變對象(有效不可變意味著對象的狀態在發布之后永遠不會被修改)。
3.獨立觀察
4.“volatile bean” 模式
結束語
與鎖相比,Volatile 變量是一種非常簡單但同時又非常脆弱的同步機制,它在某些情況下將提供優于鎖的性能和伸縮性。如果嚴格遵循 volatile 的使用條件 —— 即變量真正獨立于其他變量和自己以前的值 —— 在某些情況下可以使用
synchronized
的可見性特性,但是不具備原子特性.這就是說線程能
夠自動發現 volatile 變量的最新值.使用volatile原則:
對變量的寫操作不依賴于當前值。
該變量沒有包含在具有其他變量的不變式中
package zhang.feng.concurrent.atomic;
public class VolatileTest {
private String str="";
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
private void doit(){
new Thread(new Runnable(){
public void run() {
setStr("沒有寫入主存中");
System.out.println("====");
}
},"THREAD_ONE").start();
new Thread(new Runnable(){
public void run() {
String str=getStr();
System.out.println(str);
}
},"THREAD_TWO").start();
}
public static void main(String[] args){
VolatileTest vt=new VolatileTest();
vt.doit();
}
}
上面的例子,如果不使用volatile變量,可能出現的情況是(出現幾率很小),THREAD_ONE線程在setStr()后,THREAD_TWO執行了getStr(),但是由于并沒有將數據寫入主存中,而此時getStr()獲得的數據將是過時數據.
解決的方式,通過lock(開銷比較大),使用volatile變量(如上).
正確使用 volatile 的模式
1.狀態標志
volatile boolean shutdownRequested;

public void shutdown() { shutdownRequested = true; }
public void doWork() {
while (!shutdownRequested) {
// do stuff
}
}
可能在另一個線程中調用shutdown(),那么使用volatile可以保證shutdownRequested可見性,所以不需要使用lock來實現數據同步.
public void shutdown() { shutdownRequested = true; }
public void doWork() {
while (!shutdownRequested) {
// do stuff
}
}
該模式特征:只有一種狀態的轉換.
2.一次性安全發布
public class BackgroundFloobleLoader {
public volatile Flooble theFlooble;
public void initInBackground() {
// do lots of stuff
theFlooble = new Flooble(); // this is the only write to theFlooble
}
}
public class SomeOtherClass {
public void doWork() {
while (true) {
// do some stuff
// use the Flooble, but only if it is ready
if (floobleLoader.theFlooble != null)
doSomething(floobleLoader.theFlooble);
}
}
}
在如果initInBackground(寫入)和doWork(讀取)在不同線程同時執行時,那么可能獲得的更新后的Flooble對象也可能是未更新前的,而是用volatile可以保證是讀取到更新后的對象.public volatile Flooble theFlooble;
public void initInBackground() {
// do lots of stuff
theFlooble = new Flooble(); // this is the only write to theFlooble
}
}
public class SomeOtherClass {
public void doWork() {
while (true) {
// do some stuff

// use the Flooble, but only if it is ready
if (floobleLoader.theFlooble != null)
doSomething(floobleLoader.theFlooble);
}
}
}
該模式的一個必要條件是:被發布的對象必須是線程安全的,或者是有效的不可變對象(有效不可變意味著對象的狀態在發布之后永遠不會被修改)。
3.獨立觀察
public class UserManager {
public volatile String lastUser;
public boolean authenticate(String user, String password) {
boolean valid = passwordIsValid(user, password);
if (valid) {
User u = new User();
activeUsers.add(u);
lastUser = user;
}
return valid;
}
}
該模式可以用于收集最近一次登錄信息,并提交其他應用處理.public volatile String lastUser;
public boolean authenticate(String user, String password) {
boolean valid = passwordIsValid(user, password);
if (valid) {
User u = new User();
activeUsers.add(u);
lastUser = user;
}
return valid;
}
}
4.“volatile bean” 模式
@ThreadSafe
public class Person {
private volatile String firstName;
private volatile String lastName;
private volatile int age;
public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
public int getAge() { return age; }
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setAge(int age) {
this.age = age;
}
}
public class Person {
private volatile String firstName;
private volatile String lastName;
private volatile int age;
public String getFirstName() { return firstName; }
public String getLastName() { return lastName; }
public int getAge() { return age; }
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setAge(int age) {
this.age = age;
}
}
結束語
與鎖相比,Volatile 變量是一種非常簡單但同時又非常脆弱的同步機制,它在某些情況下將提供優于鎖的性能和伸縮性。如果嚴格遵循 volatile 的使用條件 —— 即變量真正獨立于其他變量和自己以前的值 —— 在某些情況下可以使用
volatile
代替 synchronized
來簡化代碼。然而,使用 volatile
的代碼往往比使用鎖的代碼更加容易出錯。本文介紹的模式涵蓋了可以使用 volatile
代替 synchronized
的最常見的一些用例。遵循這些模式(注意使用時不要超過各自的限制)可以幫助您安全地實現大多數用例,使用 volatile 變量獲得更佳性能。