Java多線程如何?資源共用__Java

來源:互聯網
上載者:User

Java實現多線程方式有兩種:繼承Thread類或者實現Runnable即可.線程啟動時調用start()方法.
實現Runnable介面可以實現資源共用
下面讓我們來看一下代碼:

public class Thread1 extends Thread{    private int num = 5;    @Override    public void run() {        for(int i=0;i<10;i++)        {            if(this.num>0)            {                System.out.println("剩餘的票1:"+num--);            }        }    }}public class Thread2 implements Runnable{    private int num = 5;    public void run() {        for(int i=0;i<10;i++)        {            if(this.num>0){                System.out.println("剩餘的票2:"+num--);            }        }    }}    /**     * @author 付玉偉     * @time 2015-4-9 下午09:37:56     * @param args     */    public static void main(String[] args) {        Thread1 t1 = new Thread1();        t1.setName("售票視窗1");        Thread1 t2 = new Thread1();        t1.setName("售票視窗2");        Thread1 t3 = new Thread1();        t1.setName("售票視窗3");        t1.start();        t2.start();        t3.start();        Thread2 t1_ = new Thread2();        Thread t1_1 = new Thread(t1_);        t1_1.setName("售票視窗1_");        Thread t2_2 = new Thread(t1_);        t2_2.setName("售票視窗2_");        Thread t3_3 = new Thread(t1_);        t1_1.setName("售票視窗3_");        t1_1.start();        t2_2.start();        t3_3.start();    }}

運行結果如下:

一共5張票,線程1賣了15次,顯然資源沒有共用,而線程2隻買了5次。
Java多線程訪問共用資源的方式:
1、如果每一個線程執行的代碼相同,可以使用同一個runnable對象,這個對象中有那個共用資料(買票系統)
2、如果每一個線程執行的代碼不相同,這時候需要不同的Runnable對象,有以下兩種方式來實現這些Runnable對戲之間的資料共用。
(1)、將共用資料封裝在另外一個對象中,然後將這個對象逐一傳遞給各個Runnable對象。每個線程對共用資料的操作方法也分配到那個對象身上去完成,這樣容易實現針對該資料進行的各個操作的互斥和通訊。
  (2)、將這些Runnable對象作為某一個類中的內部類,共用資料作為這個外部類中的成員變數,每個線程對共用資料的操作方法也分配給外部類,以便實現對共用資料進行的各個操作的互斥和通訊,作為內部類的各個Runnable對象調用外部類的這些方法。
  (3)、上面兩種方式的組合:將共用資料封裝在另外一個對象中,每個線程對共用資料的操作方法也分配到那個對象身上去完成,對象作為這個外部類中的成員變數或方法中的局部變數,每個線程的Runnable對象作為外部類中的成員內部類或局部內部類。
  (4)、總之,要同步互斥的幾段代碼最好是分別放在幾個獨立的方法中,這些方法再放在同一個類中,這樣比較容易實現它們之間的同步互斥和通訊。
3、極端且簡單的方式,即在任意一個類中定義一個static的變數,這將被所有線程共用
線上程操作中由於其操作的不確定性,所以提供了一個方法,可以取得當前操作線程:
public static Thread currentThread();
說明:
對於線程的名字一般是在啟動前進行設定,最好不要設定相同的名字,最好不要為一個線程改名字.
在Java執行中一個Java程式至少啟動2個線程:一個主線程和一個記憶體回收線程.
多線程的同步問題
如果使用Runnable的方式實現買票系統,在買票出現延遲時如:

public class Thread2 implements Runnable{    private int num = 5;    public void run() {        for(int i=0;i<10;i++)        {            try {                Thread.sleep(200);            } catch (InterruptedException e) {                e.printStackTrace();            }            if(this.num>0){                System.out.println("剩餘的票2:"+num--);            }        }    }}

輸出結果如下:

如果解決這樣的問題就必須使用同步,即:過個操作在同一個時間段內只有一個線程進行。
Java多線程同該方法步主要依賴於若干方法和關鍵字
1、wait方法
Object的方法,作用是使得當前調用wait方法所在部分的線程停止執行,並釋放當前所獲得調用wait的代碼塊的鎖,並在其他線程調用notify或者notifyAll方法時恢複到競爭鎖狀態
wait被調用的時候必須在擁有鎖(synchronized修飾)的代碼塊中
恢複執行後,從wait的下一條語句開始執行,因為wait方法總是應當在while迴圈中調用,以免出現恢複執行後繼續執行的條件卻不滿足繼續執行的條件。
若wait方法參數中帶時間,則除了notify和notifyAll被調用能啟用處於wait狀態的線程進入鎖競爭外,在其他線程中interrupt它或者參數時間到了之後,該線程也將啟用到競爭狀態。
wait方法被調用的線程必須獲得之前執行到wait時釋放掉用的鎖重新獲得才能夠恢複執行。
2、notify方法和notifyAll方法
notify方法通過調用了wait方法,但是尚未啟用一個線程調度隊列(即進入競爭鎖),不是立即執行。並且具體是哪一個線程不能保證。另外一點就是被喚醒的這個線程一定是等待wait所釋放的鎖。
notifyAll方法則喚醒所有調用wait方法,尚未啟用的進程進入競爭隊列。
3、synchronized關鍵字
用來標識一個普通方法時,表示一個線程要執行該方法必須取得該方法所在對象的鎖。
用來 標識一個靜態方法時,表示一個線程要執行該方法必須取得該方法所在類的類鎖
修飾一個代碼塊。類似synchronized(Obj){}表示一個線程要執行的代碼塊必須獲得Object的鎖,這樣做的目的是減小鎖的粒度,保證當不同塊所需的鎖不衝突時不用對整個對象加鎖。利用零長度的byte數組對象做obj非常經濟。
4、atomic action 原子操作
在Java中,以下都是原子操作,但是在C和C++中不是
對引用變數和除了long和double之外的未經處理資料類型變數進行讀寫
對所有聲明為volatile的變數(包括long和double)的讀寫
另外在Java.util.concurrent和java.util.concurrent.atomic包中提供了一些不依賴於同步機制的安全執行緒類和方法。
下面使用synchronized來解決同步的問題:
1、同步代碼塊

public class Thread2 implements Runnable{    private int num = 5;    public void run() {        for(int i=0;i<10;i++)        {            // 使用同步代碼塊            synchronized(this){                try {                    Thread.sleep(200);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            if(this.num>0){                System.out.println("剩餘的票2:"+num--);            }        }    }}

2、同步方法

public class Thread3 implements Runnable{    private int num = 5;    public void run() {        for(int i=0;i<10;i++){            sale();        }    }    // 使用同步方法    public synchronized void sale(){        try {            Thread.sleep(300);    //休息300毫秒        } catch (InterruptedException e) {            e.printStackTrace();        }         if(num > 0 ){            System.out.println(Thread.currentThread().getName()+"買票"+this.num--);        }    }    public static void main(String[] args){        Thread3 t3 = new Thread3();        new Thread(t3,"售票視窗1").start();        new Thread(t3,"售票視窗2").start();        new Thread(t3,"售票視窗3").start();    }}

多線程之間資源共用需要使用同步,但是過多的同步會造成死結。
死結是在多道程式系統中,一組進程中的每一個進程都無限期的等待另一個線程,所以佔有且永遠不會釋放的資源。
死結產生的原因:
1、競爭資源,系統提供的資源有限,不能滿足每一個進程的要求
2、多道程式運行時,進程推進順序不合理
產生死結的必要條件:
1、互斥資源使用
2、佔用並等待資源
3、不可搶奪資源
4、迴圈等待資源
轉自http://www.cnblogs.com/dennisit/archive/2013/02/24/2925288.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.