volatile
synchronized 只能寫在方法,而 volatile 只能寫在變數使用 volatile 宣告的變數,會在記憶體裡取値;沒宣告會在 cache 取值,所以宣告 volatile 後會比較慢
但沒宣告 volatile 有可能記憶體裡的值已被更改,造成資料不同步,所以非必要不要加
在兩個以上 (含) 的 Thread 會使用到的成員變數可以加 volatile,但如果成員變數已在 synchronized 裡或有 final 關鍵字,就不必加了
※synchronized
class ATM implements Runnable {
private Account a;
private Integer money;
public ATM(Account a, Integer money) {
this.a = a;
this.money = money;
}
@Override
public void run() {
a.executeWithDraw(a, money);
}
}
class Account {
private int totalMoney;
public Account(int money) {
this.totalMoney = money;
}
public int getTotalMoney() {
return totalMoney;
}
public void executeWithDraw(Account a, int money) {
synchronized (this) {
System.out.print("帳號:" + Thread.currentThread().getName());
int tmpTotalMoney = totalMoney;
for (int i = 1; i <= 99999; i++);
tmpTotalMoney -= money;
if (tmpTotalMoney < 0) {
System.out.println("$不夠");
} else {
totalMoney = tmpTotalMoney;
}
System.out.println("領" + money + "元, 剩" + a.getTotalMoney() + "元");
}
}
}
※for 迴圈模擬提款的時間
※synchronized 寫在方法和 synchronized() 差在,一個是整個方法都 synchronized;另一個是synchronized 區塊裡才是 synchronized,所以外面可以加一些和 synchronized 無關的程式碼,效能會比較好
※另外兩個synchronized 是 static 的,其中一個和寫在方法一樣,另一個是synchronized(Xxx.class)
※測試
Account a = new Account(10000);
System.out.println("目前共" + a.getTotalMoney() + "元");
Thread t1 = new Thread(new ATM(a, 5000));
Thread t2 = new Thread(new ATM(a, 2000));
Thread t3 = new Thread(new ATM(a, 4000));
t1.start();
t2.start();
t3.start();
※
※wait、notify、notifyAll
這三個方法都是 Object 的,都必需寫在 synchronized 裡,否則會出「java.lang.IllegalMonitorStateException」的錯
使用 wait 後,必需用 notify 或 notifyAll 喚醒,兩者差在一個呼叫一個 Thread;另一個呼叫全部的 Thread,呼叫哪一個或呼叫的 Thread 順序,是以 JVM 的算法為準,不是優先權值
wait 會釋放鎖,所以一執行完這一行,其他的 Thread 可以呼叫
public class ThreadTest extends Thread {
@Override
public void run() {
synchronized (this) {
System.out.println("call notify:" + Thread.currentThread());
notify();
}
}
public static void main(String... a) {
ThreadTest t = new ThreadTest();
t.start();
synchronized (t) {
System.out.println("call wail:" + Thread.currentThread());
try {
t.wait();
System.out.println("...");
} catch (InterruptedException e) {
System.out.println("wait interrupted!");
}
System.out.println("......");
}
}
}
※結果:
call wail:Thread[main,5,main]
call notify:Thread[Thread-0,5,main]
...
......
※Thread.currentThread 印出的是「Thread 名稱、優先權值、Thread 群組名稱」
※以喝完水要加水為例
class Water {
private static boolean empty = true;
public synchronized void put(int i) {
if (!empty) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("加第" + i + "次水");
empty = false;
notify();
}
public synchronized void eat(int i) {
if (empty) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("喝第" + i + "次水");
empty = true;
notify();
}
}
class Drink implements Runnable {
Water w;
Drink(Water c) {
this.w = c;
}
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
w.eat(i);
}
}
}
class Add implements Runnable {
Water w;
Add(Water c) {
this.w = c;
}
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
w.put(i);
}
}
}
※
※測試
Water c = new Water(); Thread p = new Thread(new Add(c)); Thread e = new Thread(new Drink(c)); e.start(); p.start();
※
沒有留言:
張貼留言