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();
※
沒有留言:
張貼留言