成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java多線程:Java多線程同步與對象控制權(quán)

joyqi / 1179人閱讀

摘要:輔助線程執(zhí)行主線程正在執(zhí)行函數(shù)函數(shù)如果對象調(diào)用了方法就會使持有該對象的線程把該對象的控制權(quán)交出去,然后處于等待狀態(tài)。當(dāng)同步方法執(zhí)行完畢或者執(zhí)行時,其他某個線程將獲得對象的訪問權(quán)。

join()函數(shù)
Join的含義是:將某一線程加入成為另一個線程的流程之一,換言之就是等待另一個線程執(zhí)行完畢。

public class JoinTest {
        public static void main(String[] args) throws InterruptedException {
              Thread otherThread = new Thread( new Runnable() {
                      public void run() {
                            try {
                                   for ( int i = 1; i <= 5; i++) {
                                         Thread. sleep(1000);
                                         System. out.println(i + ":輔助線程執(zhí)行.." );
                                  }
                           } catch (InterruptedException e) {
                                  e.printStackTrace();
                           }
                     }
              });
              otherThread.start();

               try {
                     otherThread.join();
              } catch (InterruptedException e) {
                     e.printStackTrace();
              }
               for ( int i = 1; i <= 5; i++) {
                     Thread. sleep(500);
                     System. out.println(i + ": 主線程正在執(zhí)行..." );
              }
       }
}

wait()函數(shù)notify()函數(shù)

如果對象調(diào)用了wait方法就會使持有該對象的線程把該對象的控制權(quán)交出去,然后處于等待狀態(tài)。

如果對象調(diào)用了notify方法就會通知某個正在等待這個對象的控制權(quán)的線程可以繼續(xù)運行。

wait方法阻塞本線程,等待其他線程調(diào)用notify方法通知自己可以繼續(xù)執(zhí)行,也就是說這一對方法應(yīng)該結(jié)合在一起使用,只有當(dāng)A線程在wait之后出讓資源是其他線程有機會前進,另外的B線程notifyA才能使A線程恢復(fù)執(zhí)行。在Java多線程任務(wù)里經(jīng)常會出現(xiàn)多個線程爭奪同一個資源,如果任由其爭奪可能會造成問題,所以有序的爭奪離不開阻塞和喚醒線程,可以先對線程已經(jīng)爭得的資源加鎖,這時其他資源將無法爭奪這個加鎖的資源,在試用完資源后對資源進行解鎖,使得其他線程能夠重新獲得這個資源的爭奪權(quán)。(其實這個過程類似于進程的信號量加鎖解鎖)。闡明這個問題的最好例子莫過于生產(chǎn)者消費者的模擬:

在這個過程中,生產(chǎn)產(chǎn)品、消費產(chǎn)品時所需要的容器是爭奪的資源,對這個這多資源在訪問時需要加解鎖:

synchronized(container):對容器加鎖以阻塞其他線程同時訪問,亦即使得其他線程處于等待狀態(tài);

container.wait():在容器滿時阻塞本線程把容器解鎖將容器的控制權(quán)交出去,本線程處于等待狀態(tài);

container.notify():在容器空時通知正在等待容器控制權(quán)的線程恢復(fù)運行,亦即解鎖容器;

public class ThreadTest {
    private List container = new ArrayList();

    public static void main(String[] args) {
        PCTest m = new PCTest();
        new Thread(new Consume(m.getContainer()), "消費者1").start();
        new Thread(new Product(m.getContainer()), "生產(chǎn)者1").start();
        new Thread(new Consume(m.getContainer()), "消費者2").start();
        new Thread(new Product(m.getContainer()), "生產(chǎn)者2").start();
    }

    public List getContainer() {
        return container;
    }

    public void setContainer(List container) {
        this.container = container;
    }
}

class Product implements Runnable {
    private List container = null;

    public Product(List lst) {
        this.container = lst;
    }

    public void run() {
        while (true) {
            synchronized (container) {
                if (container.size() >= 5) {
                    try {
                        container.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                container.add(new Object());
                System.out
                        .println(Thread.currentThread().getName() + "生產(chǎn)了一個產(chǎn)品");
                System.out.println("現(xiàn)在容器中一共有" + container.size() + "個產(chǎn)品");
                container.notify();

            }
        }
    }
}

class Consume implements Runnable {
    private List container = null;

    public Consume(List lst) {
        this.container = lst;
    }

    public void run() {

        while (true) {
            synchronized (container) {
                if (container.size() == 0) {
                    try {
                        container.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                container.remove(0);
                System.out
                        .println(Thread.currentThread().getName() + "消費了一個產(chǎn)品");
                System.out.println("現(xiàn)在容器中一共有" + container.size() + "個產(chǎn)品");
                container.notify();

            }
        }
    }
}

線程死鎖的問題
線程和線程如果在運行的過程中保有同樣的資源,如果這些資源的占用在某一時刻無法良好分配,那么就有可能出現(xiàn)死鎖:

class MyRunnable implements Runnable{
    Object a;
    Object b;
    public MyRunnable(Object a, Object b) {
        this.a = a;
        this.b = b;
    }
    @Override
    public void run() {
        while(true){
            synchronized (a) {
                synchronized (b) {
                    System.out.println(Thread.currentThread().getName()+" is running");
                }
            }
        }
    }
}
class ThreadTest{
    public static void main(String[] args) {
        Object a = new Object();
        Object b = new Object();
        MyRunnable myRunnable1 = new MyRunnable(a, b);
        MyRunnable myRunnable2 = new MyRunnable(b, a);
        Thread threadA = new Thread(myRunnable1,"t1");
        Thread threadB = new Thread(myRunnable2,"t2");
        threadA.start();
        threadB.start();
    }
}

在這個例子中兩個線程在運行的過程中必須同時保有兩個對象,那么當(dāng)對象A被一個線程鎖定而被另一個線程需要,同時對象B被一個線程鎖定而被另一個線程需要的時候就會出現(xiàn)死鎖。比如t1拿到A和B后鎖定它們運行,t2因為沒有A和B處于等待狀態(tài),t1運行后解鎖先解鎖B還沒有解鎖A,t2拿到這個B后鎖定B繼而需要A,t1解鎖A后t2沒有拿到A,t1的下一次循環(huán)拿到了這個A并鎖定A,這個時候t2需要的A被t1鎖定,t1需要的B被t2鎖定,最終A和B產(chǎn)生死鎖。

附上Java線程的同步原理

線程同步的基本原理

java會為每個object對象分配一個monitor,當(dāng)某個對象的同步方法(synchronized methods )或同步塊被多個線程調(diào)用時,該對象的monitor將負責(zé)處理這些訪問的并發(fā)獨占要求。
當(dāng)一個線程調(diào)用一個對象的同步方法時,JVM會檢查該對象的monitor。如果monitor沒有被占用,那么這個線程就得到了monitor的占有權(quán),可以繼續(xù)執(zhí)行該對象的同步方法;如果monitor被其他線程所占用,那么該線程將被掛起,直到monitor被釋放。
當(dāng)線程退出同步方法調(diào)用時,該線程會釋放monitor,這將允許其他等待的線程獲得monitor以使對同步方法的調(diào)用執(zhí)行下去。
注意:java對象的monitor機制和傳統(tǒng)的臨界檢查代碼區(qū)技術(shù)不一樣。java的一個類一個同步方法并不意味著同時只有一個線程獨占執(zhí)行(不同對象的同步方法可以同時執(zhí)行),但臨界檢查代碼區(qū)技術(shù)確會保證同步方法在一個時刻只被一個線程獨占執(zhí)行。
java的monitor機制的準確含義是:任何時刻,對一個指定object對象的某同步方法只能由一個線程來調(diào)用。
java對象的monitor是跟隨object實例來使用的,而不是跟隨程序代碼。兩個線程可以同時執(zhí)行相同的同步方法,比如:一個類的同步方法是xMethod(),有a,b兩個對象實例,一個線程執(zhí)行a.xMethod(),另一個線程執(zhí)行b.xMethod(). 互不沖突。
wait()、notify(),notifyAll()的使用
obj.wait()方法使本線程掛起,并釋放obj對象的monitor,只有其他線程調(diào)用obj對象的notify()或notifyAll()時,才可以被喚醒。
obj.notifyAll()方法喚醒所有阻塞在obj對象上的沉睡線程,然后被喚醒的眾多線程競爭obj對象的monitor占有權(quán),最終得到的那個線程會繼續(xù)執(zhí)行下去,但其他線程繼續(xù)等待。
obj.notify()方法是隨機喚醒一個沉睡線程,過程更obj.notifyAll()方法類似。
wait,notify和notifyAll只能在同步控制方法或者同步控制塊里面使用,
如:

synchronized(x){
    x.notify()
    //或者wait()
}

以上內(nèi)容說明了為什么調(diào)用wait(),notify(),notifyAll()的線程必須要擁有obj實例對象的monitor占有權(quán)。
每個對象實例都有一個等待線程隊列。這些線程都是等待對該對象的同步方法的調(diào)用許可。對一個線程來說,有兩種方法可以進入這個等待線程隊列。一個是當(dāng)其他線程執(zhí)行同步方法時,自身同時也要執(zhí)行該同步方法;另一個是調(diào)用obj.wait()方法。
當(dāng)同步方法執(zhí)行完畢或者執(zhí)行wait()時,其他某個線程將獲得對象的訪問權(quán)。當(dāng)一個線程被放入等待隊列時,必須要確??梢酝ㄟ^notify()的調(diào)用來解凍該線程,以使其能夠繼續(xù)執(zhí)行下去。
wait()與sleep()的區(qū)別
sleep()方法是Thread類的靜態(tài)方法,不涉及到線程間同步概念,僅僅為了讓一個線程自身獲得一段沉睡時間。sleep可以在任何地方使用。(所以sleep只跟當(dāng)前線程自己有關(guān))
wait()方法是object類的方法,解決的問題是線程間的同步,該過程包含了同步鎖的獲取和釋放,調(diào)用wait方法將會將調(diào)用者的線程掛起,直到其他線程調(diào)用同一個對象的notify()方法才會重新激活調(diào)用者。(所以wait適用于多個線程同步協(xié)調(diào)時才使用的)

注意:線程調(diào)用notify()之后,只有該線程完全從 synchronized代碼里面執(zhí)行完畢后,monitor才會被釋放,被喚醒線程才可以真正得到執(zhí)行權(quán)。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/64614.html

相關(guān)文章

  • java學(xué)習(xí)(十) —— java中的線程概述

    摘要:進程一般由程序數(shù)據(jù)集進程控制塊三部分組成。線程概述線程的出現(xiàn)是為了降低上下文切換的消耗,提高系統(tǒng)的并發(fā)性。線程突破了一個進程只能干一件事的缺陷,使到進程內(nèi)并發(fā)成為可能。進程與線程的關(guān)系進程是計算機中的程序關(guān)于某數(shù)據(jù)集合上的一次運行活動。 進程概述 進程:正在運行的程序,是系統(tǒng)進行資源分配和調(diào)用的獨立單位。 進程就是一個程序在一個數(shù)據(jù)集上的一次動態(tài)執(zhí)行過程。 進程一般由程序、數(shù)據(jù)集、進...

    Sanchi 評論0 收藏0
  • 40道阿里巴巴JAVA研發(fā)崗線程面試題詳解,你能答出

    摘要:但是單核我們還是要應(yīng)用多線程,就是為了防止阻塞。多線程可以防止這個問題,多條線程同時運行,哪怕一條線程的代碼執(zhí)行讀取數(shù)據(jù)阻塞,也不會影響其它任務(wù)的執(zhí)行。 1、多線程有什么用?一個可能在很多人看來很扯淡的一個問題:我會用多線程就好了,還管它有什么用?在我看來,這個回答更扯淡。所謂知其然知其所以然,會用只是知其然,為什么用才是知其所以然,只有達到知其然知其所以然的程度才可以說是把一個知識點...

    lpjustdoit 評論0 收藏0
  • 想進大廠?50個線程面試題,你會少?(一)

    摘要:下面是線程相關(guān)的熱門面試題,你可以用它來好好準備面試。線程安全問題都是由全局變量及靜態(tài)變量引起的。持有自旋鎖的線程在之前應(yīng)該釋放自旋鎖以便其它線程可以獲得自旋鎖。 最近看到網(wǎng)上流傳著,各種面試經(jīng)驗及面試題,往往都是一大堆技術(shù)題目貼上去,而沒有答案。 不管你是新程序員還是老手,你一定在面試中遇到過有關(guān)線程的問題。Java語言一個重要的特點就是內(nèi)置了對并發(fā)的支持,讓Java大受企業(yè)和程序員...

    wow_worktile 評論0 收藏0
  • JAVA 線程和并發(fā)基礎(chǔ)

    摘要:線程可以被稱為輕量級進程。一個守護線程是在后臺執(zhí)行并且不會阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。在的線程中并沒有可供任何對象使用的鎖和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻譯:并發(fā)編程網(wǎng) - 鄭旭東 校對:方騰飛 多...

    vboy1010 評論0 收藏0
  • JAVA 線程和并發(fā)基礎(chǔ)面試問答

    摘要:多線程和并發(fā)問題是技術(shù)面試中面試官比較喜歡問的問題之一。線程可以被稱為輕量級進程。一個守護線程是在后臺執(zhí)行并且不會阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。 多線程和并發(fā)問題是 Java 技術(shù)面試中面試官比較喜歡問的問題之一。在這里,從面試的角度列出了大部分重要的問題,但是你仍然應(yīng)該牢固的掌握Java多線程基礎(chǔ)知識來對應(yīng)日后碰到的問題。(...

    dreamans 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<