多線程中多個線程共享數據,多個線程對於共享的數據繼續操做時,若是咱們很好的控制就會發生錯誤。接下來看一個多個線程同時操做同一個數據的例子。
java
public class ThreadCount { public static void main(String[] args) { Total total = new Total(); // 建立三個線程給total分別+十、+20、+5 Counter counter1 = new Counter(10, total); Counter counter2 = new Counter(20, total); Counter counter3 = new Counter(5, total); counter1.start(); counter2.start(); counter3.start(); } } //Total類 class Total{ private int total; public void setTotal(int total) { this.total = total; } public int getTotal() { return total; } } //計算類 class Counter extends Thread { private int i; private Total total; Counter(int i, Total total) { this.i = i; this.total = total; } @Override public void run() { total.setTotal(total.getTotal() + i); System.out.println("結果爲: " + total.getTotal()); } } //咱們期待的運行結果是: 結果爲: 10 結果爲: 30 結果爲: 35 //實際的運行結果: 結果爲: 30 結果爲: 30 結果爲: 35
如今有兩種方法來解決這個問題:數組
(1)run方法添加synchronized括起來的同步代碼塊多線程
public void run() { synchronized (this) { total.setTotal(total.getTotal() + i); System.out.println("結果爲: " + total.getTotal()); } }
(2)增長一個synchronized修飾的方法構成同步方法,而後run方法調用此方法併發
public void run() { add(); } public synchronized void add() { total.setTotal(total.getTotal() + i); System.out.println("結果爲: " + total.getTotal()); }
synchronized有什麼神通:ide
(1)當兩個併發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程獲得執行。另外一個線程必須等待當前線程執行完這個代碼塊之後才能執行該代碼塊。this
(2)然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另外一個線程仍然能夠訪問該object中的非synchronized(this)同步代碼塊。spa
(3)尤爲關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其餘線程對object中全部其它synchronized(this)同步代碼塊的訪問將被阻塞。.net
(4)(3)一樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就得到了這個object的對象鎖。結果,其它線程對該object對象全部同步代碼部分的訪問都被暫時阻塞。線程
(5)以上規則對其它對象鎖一樣適用.code
根據(2)http://my.oschina.net/u/2361475/blog/543961中爲何notifyAll()必須放在synchronized代碼塊內,這是由於在ReaderResult類中已經持有了Calculator對象的鎖,若是這個時候notifyAll()沒有放在synchronized代碼塊內,這個時候會發生Calculator類中的會搶奪ReaderResult類中已經持有了Calculator對象的鎖,而鎖只有一把,固然就會報錯以下:
java.lang.IllegalMonitorStateException at java.lang.Object.notifyAll(Native Method)
使用synchronized和wait/notify/notifyAll同時使用時注意的一點,請看一個例子:
public class NotifyTest { //這裏使用了String類型,這個時候flag引用指向的對象是true private String flag = "true"; class NotifyThread extends Thread { public NotifyThread(String name) { super(name); } public void run() { try { sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (flag) { //flag的對象變爲false,對象發生改變 flag = "false"; flag.notifyAll(); } } } class WaitThread extends Thread { public WaitThread(String name) { super(name); } public void run() { synchronized (flag) { while (flag.equals("true")) { System.out.println(getName() + " begin waiting!"); long waitTime = System.currentTimeMillis(); try { flag.wait(); } catch (InterruptedException e) { e.printStackTrace(); } waitTime = System.currentTimeMillis() - waitTime; System.out.println("wait time :" + waitTime); } System.out.println(getName() + " end waiting!"); } } } public static void main(String[] args) throws InterruptedException { System.out.println("Main Thread Run!"); NotifyTest test = new NotifyTest(); NotifyThread notifyThread = test.new NotifyThread("notify01"); WaitThread waitThread01 = test.new WaitThread("waiter01"); WaitThread waitThread02 = test.new WaitThread("waiter02"); WaitThread waitThread03 = test.new WaitThread("waiter03"); notifyThread.start(); waitThread01.start(); waitThread02.start(); waitThread03.start(); } } //運行結果 Exception in thread "notify01" java.lang.IllegalMonitorStateException at java.lang.Object.notifyAll(Native Method)
問題主要是flag引用的對象發生了改變,咱們如何選擇synchoronize的鎖呢,其實只要咱們將flag換爲javaBean就行,如今爲了方便起見咱們使用String數組private String flag[] = {"true"}這樣也能夠解決問題。
看一下正常執行的結果:
public class NotifyTest { private String flag[] = {"true"}; class NotifyThread extends Thread { public NotifyThread(String name) { super(name); } public void run() { try { sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (flag) { flag[0] = "false"; flag.notifyAll(); } } } class WaitThread extends Thread { public WaitThread(String name) { super(name); } public void run() { synchronized (flag) { while (flag[0].equals("true")) { System.out.println(getName() + " begin waiting!"); long waitTime = System.currentTimeMillis(); try { flag.wait(); } catch (InterruptedException e) { e.printStackTrace(); } waitTime = System.currentTimeMillis() - waitTime; System.out.println("wait time :" + waitTime); } System.out.println(getName() + " end waiting!"); } } } public static void main(String[] args) throws InterruptedException { System.out.println("Main Thread Run!"); NotifyTest test = new NotifyTest(); NotifyThread notifyThread = test.new NotifyThread("notify01"); WaitThread waitThread01 = test.new WaitThread("waiter01"); WaitThread waitThread02 = test.new WaitThread("waiter02"); WaitThread waitThread03 = test.new WaitThread("waiter03"); notifyThread.start(); waitThread01.start(); waitThread02.start(); waitThread03.start(); } } //執行結果 Main Thread Run! waiter01 begin waiting! waiter02 begin waiting! waiter03 begin waiting! wait time :1999 waiter03 end waiting! wait time :2000 waiter02 end waiting! wait time :2000 waiter01 end waiting!
java中那個對象是纔是鎖你們能夠轉向下面的鏈接:
http://blog.csdn.net/fyxxq/article/details/8496811