java線程同步操作實(shí)例詳解
本文實(shí)例講述了java線程同步操作。分享給大家供大家參考,具體如下:
java線程同步
public class Hello { public static void main(String[] args) { MyRun myRun0 = new MyRun(); new Thread(myRun0, "Thread0").start(); new Thread(myRun0, "Thread1").start(); new Thread(myRun0, "Thread2").start(); } } class MyRun implements Runnable { private int k = 0; @Override public void run() { for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName() + "**********" + i); k++; if (k <= 3) { if ("Thread0".equals(Thread.currentThread().getName())) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "," + k); } } } }
輸出結(jié)果
Thread0**********0
Thread1**********0
Thread2**********0
Thread1,2
Thread2,3
Thread1**********1
Thread2**********1
Thread2**********2
Thread1**********2
Thread0,7
Thread0**********1
Thread0**********2
說(shuō)明多線程在某些場(chǎng)景是存在問(wèn)題的,有時(shí)候需要線程同步。
同步 synchronized
同步代碼塊,synchronized(obj){}
,obj是一個(gè)對(duì)象,在這里就相當(dāng)于一把鎖,表示一旦有進(jìn)程搶到了這把鎖的鑰匙(就是進(jìn)入了代碼塊),其他進(jìn)程將無(wú)法進(jìn)入該鎖的代碼塊(當(dāng)前代碼塊其他進(jìn)程一定是進(jìn)不來(lái)了,其他地方的代碼塊如果也是用了這把鎖,同樣進(jìn)不去),只有代碼塊執(zhí)行完,釋放鎖后,所有進(jìn)程再重新?lián)岃€匙。
注意,上同一把鎖的代碼塊都會(huì)被鎖住,這些代碼塊可能寫(xiě)在不同方法不同位置上。
被同步代碼塊包住的代碼多個(gè)線程只能順次進(jìn)入。
synchronized (this) { k++; if (k <= 3) { if ("Thread0".equals(Thread.currentThread().getName())) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "," + k); } }
this
表示當(dāng)前對(duì)象,這里考慮的只是運(yùn)行這個(gè)方法,不涉及其它類也不涉及這個(gè)類的其它地方需要同步問(wèn)題,所以用this
也是可以的。k增加和輸出一個(gè)流程內(nèi)只能有一個(gè)線程在訪問(wèn),所以可以得到想要的輸出結(jié)果
輸出結(jié)果
Thread0**********0
Thread1**********0
Thread2**********0
Thread0,1
Thread0**********1
Thread2,2
Thread2**********1
Thread1,3
Thread1**********1
Thread0**********2
Thread2**********2
Thread1**********2
對(duì)方法進(jìn)行同步,如果存在多線程,每個(gè)線程順次訪問(wèn)該方法
注意,如果一個(gè)類里面存在多個(gè)同步方法,那么這些同步方法的鎖是一個(gè),都是當(dāng)前對(duì)象,所以不同線程想同時(shí)訪問(wèn)同一對(duì)象的不同方法也是不行的,因?yàn)檫@些方法都上了同一把鎖,但是鑰匙只有一把,只能一個(gè)線程持有。
@Override public synchronized void run() { for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName() + "**********" + i); k++; if (k <= 3) { if ("Thread0".equals(Thread.currentThread().getName())) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "," + k); } } }
輸出結(jié)果
Thread0**********0
Thread0,1
Thread0**********1
Thread0,2
Thread0**********2
Thread0,3
Thread2**********0
Thread2**********1
Thread2**********2
Thread1**********0
Thread1**********1
Thread1**********2
死鎖
public class Hello { public static void main(String[] args) { A a = new A(); B b = new B(); new Thread(new MyRun(a,b)).start(); new Thread(new MyRun1(a,b)).start(); } } class MyRun implements Runnable{ private A a; private B b; public MyRun(A a, B b) { this.a = a; this.b = b; } @Override public void run(){ a.say(b); } } class MyRun1 implements Runnable { private A a; private B b; public MyRun1(A a, B b) { this.a = a; this.b = b; } @Override public void run() { b.say(a); } } class A{ public synchronized void say(B b){ System.out.println("A要知道B的信息"); b.info(); } public synchronized void info(){ System.out.println("這是A"); } } class B{ public synchronized void say(A a){ System.out.println("B要知道A的信息"); a.info(); } public synchronized void info(){ System.out.println("這是B"); } }
如果兩個(gè)線程同時(shí)進(jìn)入了兩個(gè)say方法,就是出現(xiàn)死鎖。
關(guān)鍵點(diǎn)在于一個(gè)對(duì)象的多個(gè)同步方法具有相同的鎖,都是當(dāng)前對(duì)象。也就是x線程在訪問(wèn)a對(duì)象的say方法過(guò)程中,y線程是無(wú)法訪問(wèn)a對(duì)象的info方法的,因?yàn)殚_(kāi)鎖的鑰匙已經(jīng)被x線程搶占了。
上面的程序,如果線程x,y同時(shí)進(jìn)入了兩個(gè)say方法,a對(duì)象同步方法的鎖被線程x搶占,b對(duì)象同步方法的鎖被線程y搶占,此時(shí)線程x無(wú)法訪問(wèn)b對(duì)象的同步方法,線程y無(wú)法訪問(wèn)a對(duì)象的同步方法。代碼中恰好想要訪問(wèn),所以就出現(xiàn)死鎖了。
更多java相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Java進(jìn)程與線程操作技巧總結(jié)》、《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java操作DOM節(jié)點(diǎn)技巧總結(jié)》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總》
希望本文所述對(duì)大家java程序設(shè)計(jì)有所幫助。
- Java后臺(tái)線程操作示例【守護(hù)線程】
- Java中join線程操作實(shí)例分析
- Java使用Callable和Future創(chuàng)建線程操作示例
- 詳解Java多線程編程中線程的啟動(dòng)、中斷或終止操作
- Java線程的start方法回調(diào)run方法的操作技巧
- Java多線程編程中使用Condition類操作鎖的方法詳解
- Java8并行流中自定義線程池操作示例
- Java使用Thread創(chuàng)建多線程并啟動(dòng)操作示例
- Java線程協(xié)調(diào)運(yùn)行操作實(shí)例詳解
- Java線程操作的常見(jiàn)方法【線程名稱獲取、設(shè)置、線程啟動(dòng)判斷等】
相關(guān)文章
Spring中如何獲取request的方法匯總及其線程安全性分析
這篇文章主要給大家介紹了關(guān)于Spring中如何獲取request的方法匯總及其線程安全性分析的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-04-04Java多線程之scheduledThreadPool的方法解析
這篇文章主要介紹了Java多線程之scheduledThreadPool的方法解析,queue是DelayedWorkQueue,但通過(guò)后面的分析可以知道,最大線程數(shù)是不起作用的,最多會(huì)起核心線程數(shù)的數(shù)量,需要的朋友可以參考下2023-12-12Java實(shí)現(xiàn)的模糊匹配某文件夾下的文件并刪除功能示例
這篇文章主要介紹了Java實(shí)現(xiàn)的模糊匹配某文件夾下的文件并刪除功能,涉及java針對(duì)目錄與文件的遍歷、匹配、判斷、刪除等相關(guān)操作技巧,需要的朋友可以參考下2018-02-02淺談Java 類中各成分加載順序和內(nèi)存中的存放位置
下面小編就為大家?guī)?lái)一篇淺談Java 類中各成分加載順序和內(nèi)存中的存放位置。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02Springboot中實(shí)現(xiàn)接口冪等性的4種方案小結(jié)
本文主要介紹了Springboot中實(shí)現(xiàn)接口冪等性,包含數(shù)據(jù)庫(kù)的冪等,數(shù)據(jù)庫(kù)的冪等,Redis的冪等性和Token + 時(shí)間戳的冪等性,具有一定的參考價(jià)值,感興趣的可以了解一下2024-03-03Spring?Boot?教程之創(chuàng)建項(xiàng)目的三種方式
這篇文章主要分享了Spring?Boot?教程之創(chuàng)建項(xiàng)目的三種方式,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-05-05java正則表達(dá)式表單驗(yàn)證類工具類(驗(yàn)證郵箱、手機(jī)號(hào)碼、qq號(hào)碼等)
這篇文章主要介紹了java使用正則表達(dá)式進(jìn)行表單驗(yàn)證工具類,可以驗(yàn)證郵箱、手機(jī)號(hào)碼、qq號(hào)碼等方法,需要的朋友可以參考下2014-04-04mybatis利用association或collection傳遞多參數(shù)子查詢
今天小編就為大家分享一篇關(guān)于mybatis利用association或collection傳遞多參數(shù)子查詢,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03