java多線程編程

來源:互聯網
上載者:User

標籤:one   dex   lin   block   spl   runnable   clear   繼承   機制   

1. 多線程編程

2. Thread和Runnable

 java中實現多線程的方式有兩種,繼承Thread類、實現Runnable介面

2.1 Thread

開發人員可以編寫一個類繼承Thread,並重寫run方法,在run方法裡面編寫線程將要執行的代碼。

建立線程對象後,只需要調用start()方法即可讓線程進入就緒隊列,等待作業系統調度。

需要特別注意的是調度具有隨機性和隨時性。也就是說無法確定下一次調度哪個線程,也無法確定什麼時刻進行調度

public class MyThreadTest {    public static void main(String[] args) {        MyThread myThread = new MyThread();        myThread.start();//把myThread加入到就緒隊列裡面    }}class MyThread extends Thread {    @Override    public void run() {        System.out.println("MyThread執行了");    }}
2.2 Runnable

除了繼承Thread重寫run方法外,在簡單的情況下,還可通過實現Runnable介面的方式編寫線程執行的代碼

Thread thread = new Thread(new Runnable() {    @Override    public void run() {        System.out.println("Runnable介面方式實現多線程");    }});
3.安全執行緒問題

一個資料,如一個對象或對象中的某個欄位,如果有多個線程可以同時訪問它,就可能會出現安全執行緒問題:資料錯亂、程式出錯或其他無法預知的問題

比如線程1要遍曆一個list,線程2要把這個list清空,如果這兩個線程同時執行就可能會出現安全執行緒問題

public class ThreadQuestionTest {    public static void main(String[] args) {        List<Integer> list = new ArrayList<Integer>();        for (int i = 0; i < 100000; i++) {            list.add(i);        }        Thread thread1 = new Thread(new Runnable() {            @Override            public void run() {                for (int i = 0; i < list.size(); i++) {                    System.out.println(list.get(i));                }            }        });        Thread thread2 = new Thread(new Runnable() {            @Override            public void run() {                list.clear();            }        });        thread1.start();        thread2.start();    }}

輸出:

0nullnullnullnull...
4. 線程同步

線程同步控制,即使用某種方式使得一個線程在操作完某個資料前,別的線程無法操作這個資料,從而避免多個線程同時操作一個資料,進而避免安全執行緒問題

線程同步控制的方式有同步鎖機制、等待/通知機制、訊號量機制等,它們應用在不同複雜度的情境下

4.1同步代碼塊

synchronized同步鎖機制

Java中每個對象都有一把鎖,同一時刻只能有一個線程持有這把鎖。線程可以使用synchronized關鍵字向系統申請某個對象的鎖,得到鎖之後,別的線程再申請該鎖時,就只能等待。持有鎖的線程在這次操作完成後,可以釋放鎖,以便其他線程可以獲得鎖

synchronized有兩種形式,synchronized代碼塊和synchronized方法

synchronized代碼塊,又稱同步代碼塊:

public class SynchronizedBlockTest {    public static void main(String[] args) {        List<Integer> list = new ArrayList<Integer>();        for (int i = 0; i < 100000; i++) {            list.add(i);        }        Thread thread1 = new Thread(new Runnable() {            @Override            public void run() {                synchronized (list) {                    for (int i = 0; i < list.size(); i++) {                        System.out.println(list.get(i));                    }                }            }        });        Thread thread2 = new Thread(new Runnable() {            @Override            public void run() {                synchronized (list) {                    list.clear();                }            }        });        thread1.start();        thread2.start();    }}
View Code4.2 同步方法
public class SynchronizedMethodTest {    public static void main(String[] args) {        Data data = new Data();        Thread thread1 = new Thread(new Runnable() {            @Override            public void run() {                data.bianliList();            }        });        Thread thread2 = new Thread(new Runnable() {            @Override            public void run() {                data.clearList();            }        });        thread1.start();        thread2.start();    }}class Data {    private List<Integer> list;    public Data() {        list = new ArrayList<Integer>();        for (int i = 0; i < 100000; i++) {            list.add(i);        }    }    public synchronized void bianliList() {        for (int i = 0; i < list.size(); i++) {            System.out.println(list.get(i));        }    }    public synchronized void clearList() {        list.clear();    }}
View Code

非靜態同步方法申請的鎖是類的當前對象的鎖,靜態同步方法申請的鎖是類的Class對象的鎖。同步方法執行完後即向系統歸還鎖

synchronized代碼塊和synchronized方法的效果一樣,可根據具體情境靈活選用 

對於簡單的需要線程同步控制的應用情境,synchronized基本夠用

但需要注意,所有需要同步的線程必須都申請同一個對象的鎖,當申請不同的鎖或者有的線程沒有使用synchronized時,同步鎖機制就會失效

5. wait/notify 等待/通知機制

對於稍複雜的情況,比如多個線程需要相互合作有規律的訪問共用資料,就可以使用wait/notify機制,即等待/通知機制,也稱等待/喚醒機制

 

等待/通知機制建立在synchronized同步鎖機制的基礎上,即在同步代碼塊(或同步方法)內,如果當前線程執行了lockObject.wait()(lockObject表示提供鎖的對象),則當前線程立即暫停執行,並被放入阻塞隊列,並向系統歸還所持有的鎖,並在lockObject上等待,直到別的線程調用lockObject.notify()

 

如果有多個線程在同一個對象上等待,notify()方法只會隨機通知一個等待的線程,也可以使用notifyAll()方法通知所有等待的線程。被通知的線程獲得鎖後會進入就緒隊列

public class WaitNotifyTest {    public static void main(String[] args) {        Object lockObject = new Object();        Thread thread1 = new Thread(new Runnable() {            @Override            public void run() {                synchronized (lockObject) {                    try {                        System.out.println("線程1即將開始在lockObject上等待");                        lockObject.wait();                        System.out.println("線程1收到通知並獲得鎖,開始繼續執行");                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });        Thread thread2 = new Thread(new Runnable() {            @Override            public void run() {                synchronized (lockObject) {                    System.out.println("線程2將隨機通知在lockObject上等待的線程");                    lockObject.notify();                }            }        });        thread2.start();        thread1.start();    }}
View Code5.1 wait/notify-生產者消費者執行個體

一個很典型的生產者消費者例子:現有一個生產者、一個消費者、10個盤子(緩衝區),生產者把生產的產品放入空盤子中,當沒有空盤子時就停止生產;消費者消費盤子中的產品,當所有的盤子都是空盤子時就停止消費

public class ProducerConsumerTest{    public static void main(String[] args) {        List<Integer> buffer = new LinkedList<Integer>();        int maxSize = 10;        Producer producer = new Producer(buffer, maxSize);        Consumer consumer = new Consumer(buffer);        producer.start();        consumer.start();    }}//類比生產者class Producer extends Thread {    private List<Integer> buffer; //緩衝區,表示多個盤子    private int maxSize; //表示盤子個數    public Producer(List<Integer> buffer, int maxSize) {        this.buffer = buffer;        this.maxSize = maxSize;    }    @Override    public void run() {        int id = 0;        while (true) {            synchronized (buffer) {                if (buffer.size() < maxSize) {//有空盤子則繼續生產                    id++;//表示生產了一個產品                    buffer.add(id); //表示把產品放入一個空盤子中                    System.out.println("生產產品" + id + "並通知消費者可以消費了");                    buffer.notify(); //通知消費者有產品可以消費了                } else {                    //如果沒有空盤子則等待                    System.out.println("沒有空盤子了,生產者停止生產產品");                    try {                        buffer.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }    }}//類比消費者class Consumer extends Thread {    private List<Integer> buffer; //緩衝區,表示多個盤子    public Consumer(List<Integer> buffer) {        this.buffer = buffer;    }    @Override    public void run() {        while (true) {            synchronized (buffer) {                if (buffer.size() > 0) { //有不空的盤子                    int id = buffer.remove(0); //表示消費了一個產品                    System.out.println("消費產品" + id + "並通知生產者有空盤了");                    buffer.notify();                } else {                    //全部都是空盤子則等待                    System.out.println("全部都是空盤子,消費者停止消費產品");                    try {                        buffer.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }    }}
View Code

 

java多線程編程

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.