1.線程同步ide
關鍵字:synchronizedthis
百度一下:synchronized 關鍵字,表明這個方法加鎖,至關於無論哪個線程(例如線程A),運行到這個方法時,都要檢查有沒有其它線程B(或者C、 D等)正在用這個方法(或者該類的其餘同步方法),有的話要等正在使用synchronized方法的線程B(或者C 、D)運行完這個方法後再運行此線程A,沒有的話,鎖定調用者,而後直接運行。它包括兩種用法:synchronized 方法和 synchronized 塊。spa
保證當前線程完整執行該方法後,才能由其餘線程調用。線程
2.以銀行存取款爲例code
public class Bank { private String account; private Integer balance; public Bank(String account, Integer balance) { this.account = account; this.balance = balance; } public String getAccount() { return account; } public void setAccount(String account) { this.account = account; } public Integer getBalance() { return balance; } public void setBalance(Integer balance) { this.balance = balance; } @Override public String toString() { return "Bank{" + "account='" + account + '\'' + ", balance=" + balance + '}'; } //存100 public void saveAccount(){
//加上延時,模擬更加真實 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } setBalance(this.getBalance()+100); System.out.println("存款後:"+getBalance()); } public void drawAccount(){ Integer temp= getBalance()-200;
//加上延時,模擬更加真實
try { Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} setBalance(temp); System.out.println("取款後:"+getBalance()); } }
//存款 class Save implements Runnable{ private Bank bank; public Save(Bank bank){ this.bank=bank; } @Override public void run() { bank.saveAccount(); } } //取款 class Draw implements Runnable{ private Bank bank; public Draw(Bank bank){ this.bank=bank; } @Override public void run() { bank.drawAccount(); } } public class BankTest { public static void main(String[] args) { Bank bank=new Bank("Sir li",1000); Save save=new Save(bank); Draw draw=new Draw(bank); Thread thread=new Thread(save); Thread thread1=new Thread(draw); thread.start(); thread1.start(); try { thread.join(); thread1.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(bank); } }
運行結果:blog
存款後:1100 取款後:1100 Bank{account='Sir li', balance=1100}
能夠看到程序是:在執行了saveAccount()後,balance=1000+100, 在準備執行drawAccount()時,碰到了延時,沒有執行 setBalance(temp),直接執行輸出語句,最後時主線程中的語句,join()保證了線程的執行順序沒有問題,可是跳過了方法中某些語句的執行。get
解決辦法:同步
關鍵字:synchronized 。給方法加鎖it
運行結果:正常io
存款後:1100 取款後:900 Bank{account='Sir li', balance=900}
3.線程間通訊
關鍵字:wait(),死鎖,notify(),notifyAll()
舉例:生產與消費。 生產n個,消費 n個,來看看程序如何處理
public class Queue { private int n; public synchronized int getN() { System.out.println("消費"+n); return n; } public synchronized void setN(int n) { System.out.println("生產"+n); this.n = n; } }
class Producer implements Runnable{ private Queue queue; public Producer(Queue queue){ this.queue=queue; } @Override public void run() { int i=0; while (true){ queue.setN(i++); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } class Consumer implements Runnable{ private Queue queue; public Consumer(Queue queue){ this.queue=queue; } @Override public void run() { while (true){ queue.getN(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public class ProducerTest { public static void main(String[] args) { Queue queue=new Queue(); Producer producer=new Producer(queue); Consumer consumer=new Consumer(queue); Thread thread=new Thread(producer); Thread thread1=new Thread(consumer); thread.start(); thread1.start(); } }
運行結果
生產0
消費0
生產1 //生產一次消費了兩次,程序仍是有問題的
消費1
消費1
生產2
消費2
程序應該知足這樣的要求:在沒有生產的時候是不能消費的,消費的線程須要」等待「。一樣在沒有被消費以前,也是不能生產的,生產線程須要的」等待「。
public class Queue { private int n; boolean isHave=false;// 增長判斷條件 public synchronized int getN() { if (!isHave){ try { wait(); //當沒有生產的時候,進入阻塞狀態 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("消費"+n); isHave=false; return n; } public synchronized void setN(int n) { if(isHave){ try { wait(); //在沒有消費的時候,進行阻塞狀態 } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("生產"+n); this.n = n; isHave=true; } }
運行結果:
生產0
消費0
生產1
消費1
生產2//程序中止輸出了,這時候進入了死鎖狀態,線程之間都在互相等待,須要執行喚醒操做
解決辦法:
在getN(),setN()方法中添加:notifyAll();//喚醒線程
結果正常了。。。
4.總結
join():會讓當前線程執行完畢,再去執行別的線程。保證了線程的執行順序。
sychronized: 讓被修飾的方法完整的執行。
wait():從功能來看,與判斷組合,它也保證了線程的執行順序。
死鎖:程序由於遭到線程都在「等待」狀態,而沒法運行的狀況。