日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 多线程初探(二) - 通讯与协调

發布時間:2025/5/22 java 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 多线程初探(二) - 通讯与协调 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java中線程共有5中狀態:

  • 新建:當創建一個線程對象時,新線程對象就處于新建狀態,并獲得除CPU外所需的資源。
  • 就緒:當處于新建狀態的線程被啟動后,將進入線程隊列等待CPU資源。這時它就具備了運行條件,一旦獲得CPU資源,就可以脫離創建它的主線程獨立運行。另外原來處于阻塞狀態的線程結束阻塞狀態后,也進入就緒狀態。
  • 運行:當一個就緒狀態的線程獲得CPU資源時,就進入了運行狀態。每個線程對象都有一個run方法,一旦線程開始運行,就會自動運行該方法。run()中定義了具體的線程操作。
  • 阻塞:一個正在運行的線程因為某種特殊的原因,比如遇到優先級高的線程、某種資源無法滿足時就會讓出CPU并停止自身的運行,進入阻塞狀態。只有當引起阻塞的原因消除時,它才能重新進入就緒狀態。
  • 死亡:不具備繼續運行能力的線程處于死亡狀態。一般由兩種情況引起:run()方法運行完畢;其他線程強制終止它。
  • 就緒隊列:處于就緒狀態的線程都在就緒隊列中等待CPU資源,而一般就緒隊列中會有多個線程。為此,系統會給每一個線程分配一個優先級,優先級高的可以排在較前面的位置,能優先得到CPU資源。對于優先級相同的線程,一般按照先來先服務的原則調度。

    進程和線程最大的區別在于進程是由操作系統來控制的,而線程是由進程來控制的,所以是由程序員來控制的。進程都是相互獨立的,各自享有各自的內存空間。而一個進程中的多個線程是共享內存空間的,他們可以訪問相同的變量和對象。本來這樣的設計方便了線程間的通訊,但卻帶來了新的問題:多個線程同時訪問一個變量可能出現意想不到的錯誤,如死鎖。所以多線程操作要注意協調與配合,進行互斥和同步處理。

    • 互斥:當多個線程需要訪問同一資源時,而這一資源在某一時刻只允許一個線程訪問,那么這些線程就是互斥。如線程A需要讀取變量count,而線程B會給count賦值,那邊A和B是互斥的。
    • 同步:多個線程需要訪問同一資源,而且需要相互配合才能正常工作,這些線程運行時就是一種同步關系。例如,A線程需要從緩沖區中讀取數據,而B線程需要向緩沖區中寫數據,但緩沖區的大小是固定的。
    • 臨界區:為了實現線程間的互斥和同步,需要將共享資源放入一個區域,該區域一次只允許一個線程進入,該區域就被稱為臨界區域。線程在訪問共享資源前需要進行檢查,看自己是否有權訪問資源,如果有權訪問還要阻止其他線程進入該區域。該代碼段就是臨界區。
    • 死鎖:若多個線程相互等待其他線程釋放資源,而所有線程又都不釋放自己所占的資源,從而導致相關線程處于永遠等待的狀態,這種現象稱為線程死鎖。

    線程通訊

    線程間互斥和同步必須使用信號量,Java中信號量需要用戶自己管理,系統只提供了起到PV原語作用的方法:

    • void notify():喚醒在此對象監視器上等待的某一個線程.具體是哪一個可以認為是不確定的.
    • void notifyAll():喚醒在此對象監視器上等待的所有線程。
    • void wait():導致當前的線程等待,直到其他線程調用此對象的 notify()方法或 notifyAll()方法.

    wait會釋放占有的資源(鎖),notify和notifyAll不會釋放占用的資源(鎖).而線程睡眠(sleep)時,也都不會釋放資源(鎖)。

    除了三個方法,還有一個常用的關鍵字:synchronized.

    凡是被synchronized標志的資源,都是臨界區,在同一時刻只能有一個線程能夠進入該臨界區。synchronized可以用于數據、方法,甚至是一段代碼。synchronized也被稱為“對象鎖”,而且上面的三個方法都只能使用在由synchronized標志的代碼塊中,否則會發生如下異常:

    java.lang.IllegalMonitorStateException: current thread not owner

    synchronized是和一個鎖對象關聯的,一個對象只有一個鎖。當程序運行到synchronized同步方法或代碼塊時就會檢查鎖,如果一個線程獲得該鎖,就沒有其他線程可以獲得鎖,直到第一個線程釋放(或返回)鎖。這也意味著任何其他線程都不能進入該對象上的synchronized方法或代碼塊,直到該鎖被釋放。

    如myThread.java文件代碼:

    public class myThread extends Thread {private static int count=0;private static Object o=new Object();//定義一個Object對象,用于鎖 @Overridepublic void run() {synchronized(o){for(int i=0;i<20;i++){count+=1;System.out.println("My name is "+this.getName()+" count= "+count); try {sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}}public myThread(String arg0) {super(arg0);} }

    啟動線程代碼如下:

    myThread tf=new myThread("first"); myThread ts=new myThread("secod"); tf.start(); ts.start();

    執行的結果:

    My name is secod count= 1 My name is secod count= 2 ..... ..... My name is secod count= 20 My name is first count= 21 My name is first count= 22 My name is first count= 23 ..... ..... My name is first count= 40

    myThread.java文件中的for循環使用synchronized標志,是臨界區,第一次進入的是secod線程,知道執行完畢釋放鎖,first線程才進入臨界區。

    synchronized可以用于方法、數據,甚至是代碼塊:

    • synchronized限制static方法的時候,鎖對象為這個類的class變量,相當于XXXClass.class. 例如: public static synchronized int setName(String name){Xxx.name = name; } 等價于: public static int setName(String name){synchronized(Xxx.class){Xxx.name = name;} }
    • synchronized限制非static方法的時候,鎖對象為這個類的實例(相當于this).例如: public synchronized int getX() {return x++; } 等價于: public int getX() {synchronized (this) {return x;} }
    • synchronized限制一個對象實例的時候,如(synchronized (xlock)),鎖對象為指定的這個對象實例,如xlock.

    synchronized限制static方法的時候,在某一時刻,同一個虛擬機只能有一個線程正在執行這個static方法,因為鎖對象是這個class的XXXClass.class實例,一個虛擬機只有一個XXXClass.class實例

    如果把myThread.java文件代碼改成如下:

    public class myThread extends Thread {private static int count=0;private static Object o=new Object();//定義一個Object對象,用于鎖 @Overridepublic synchronized void run() {for(int i=0;i<20;i++){count+=1;System.out.println("My name is "+this.getName()+" count= "+count); try {sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}public myThread(String arg0) {super(arg0);} }

    執行的結果:

    My name is first count= 1 My name is secod count= 2 My name is secod count= 3 My name is first count= 4 My name is first count= 5 My name is secod count= 6 My name is secod count= 7 ..... ..... My name is secod count= 34 My name is first count= 35 My name is secod count= 36 My name is secod count= 37 My name is first count= 38 My name is first count= 39 My name is secod count= 40

    可見是交叉執行的,那是因為synchronized限制某一個類的非static方法的時候,對這個類的某一特定實例,在某一時刻,同一個虛擬機只能有一個線程正在執行這個方法,但是可以同時執行多個實例的這個特定方法,因為鎖對象不同.

    轉載于:https://www.cnblogs.com/zhaiqianfeng/archive/2012/08/17/4617055.html

    總結

    以上是生活随笔為你收集整理的Java 多线程初探(二) - 通讯与协调的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。