線程同步,線程間的通訊

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():從功能來看,與判斷組合,它也保證了線程的執行順序。

死鎖:程序由於遭到線程都在「等待」狀態,而沒法運行的狀況。

相關文章
相關標籤/搜索