線程系列3--Java線程同步通信技術

? ? ? ?上一篇文章我們講解了線程間的互斥技術,使用關鍵字synchronize來實現線程間的互斥技術。根據不同的業務情況,我們可以選擇某一種互斥的方法來實現線程間的互斥調用。例如:自定義對象實現互斥(synchronize("自定義對象"){}),同一個類實例對象(synchronize(this){}),類的字節碼對象(synchronize(字節碼對象){})。這三種方法均可實現線程間的互斥,我們實際運用中靈活使用。

下面進入今天的正題:線程--線程間的同步通信技術;我們還是以傳智播客中的代碼為例來講解,子線程運行10次,主線程運行10次,如此交替運行50次。

首先看不適用同步技術時的問題代碼:

public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {for(int i=1;i<=50;i++){for(int j=1;j<=10;j++){System.out.println("子線程:"+Thread.currentThread().getName()+"運行第"+i+"次,重復第"+j+"次");}}}}).start();for(int i=1;i<=50;i++){for(int j=1;j<=10;j++){System.out.println("主線程:"+Thread.currentThread().getName()+"運行第"+i+"次,重復第"+j+"次");}}
}

上面代碼的運行結果可知,子線程與主線程間是雜亂無章的運行,顯然不能滿足我的要求。那我們來稍作調整。代碼如下:

public class ThreadSynchronizedTechnology {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {for(int i=1;i<=50;i++){
                       //使用類的字節碼作為互斥對象synchronized(ThreadSynchronizedTechnology.class){for(int j=1;j<=10;j++){System.out.println("子線程:"+Thread.currentThread().getName()+"運行第"+i+"次,重復第"+j+"次");}}}}}).start();for(int i=1;i<=50;i++){synchronized(ThreadSynchronizedTechnology.class){for(int j=1;j<=10;j++){System.out.println("主線程:"+Thread.currentThread().getName()+"運行第"+i+"次,重復第"+j+"次");}}}}}

上面的代碼我們使用類的字節碼作為互斥對象,顯然程序不再是雜亂無章的運行,子線程與主線程都能完整的運行完,但是沒有實現我們要求的交替運行,不要急我接著調整,我非常喜歡張孝祥老師循序漸進的講課方式(我不是托,是發自內心的),下面我們接著調整:

public class ThreadSynchronizedTechnology {public static void main(String[] args) {final Songzl song = new Songzl();new Thread(new Runnable() {@Overridepublic void run() {for(int i=1;i<=50;i++){song.sub(i);}}}).start();for(int i=1;i<=50;i++){song.main(i);}}
}
class Songzl{//子線程運行的方法public void sub(int i){synchronized(Songzl.class){for(int j=1;j<=10;j++){System.out.println("子線程:"+Thread.currentThread().getName()+"運行第"+i+"次,重復第"+j+"次");}}}//主線程運行的方法public void main(int i){synchronized(Songzl.class){for(int j=1;j<=10;j++){System.out.println("主線程:"+Thread.currentThread().getName()+"運行第"+i+"次,重復第"+j+"次");}}}
}

打印結果依然不是交替運行,我調成這樣是為了體現編程的面向對象思想,將相關聯的方法封裝到同一個類中,方便代碼運維。我們接著調整代碼:

public class ThreadSynchronizedTechnology {public static void main(String[] args) {final Songzl song = new Songzl();new Thread(new Runnable() {@Overridepublic void run() {for(int i=1;i<=50;i++){song.sub(i);}}}).start();for(int i=1;i<=50;i++){song.main(i);}}
}
class Songzl{//實現線程同步通信,互斥的方法共享次變量private boolean jiaoti = true;//子線程運行的方法:同一個類中方法互斥,類似與synchronized(this){}public synchronized void sub(int i) {if(!jiaoti){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}for(int j=1;j<=10;j++){System.out.println("子線程:"+Thread.currentThread().getName()+"運行第"+i+"次,重復第"+j+"次");}jiaoti = false;this.notify();}//主線程運行的方法:同一個類中方法互斥,類似與synchronized(this){}public synchronized void main(int i){if(jiaoti){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}for(int j=1;j<=10;j++){System.out.println("主線程:"+Thread.currentThread().getName()+"運行第"+i+"次,重復第"+j+"次");}jiaoti = true;this.notify();}
}

打印結果可見,已經實現子線程和主線程有條不紊的交替運行,線程間既能互斥,同時又可以相互同步通信運行;線程的互斥是通過synchronized實現的,線程間的同步通信是兩個線程間共同持有一個變量來實現的。但是線程有一個“假喚醒”的情況,雖然發生率低,但是我們不能忽略,繼續調整代碼:

public class ThreadSynchronizedTechnology {public static void main(String[] args) {final Songzl song = new Songzl();new Thread(new Runnable() {@Overridepublic void run() {for(int i=1;i<=50;i++){song.sub(i);}}}).start();for(int i=1;i<=50;i++){song.main(i);}}
}
class Songzl{//實現線程同步通信,互斥的方法共享次變量private boolean jiaoti = true;//子線程運行的方法:同一個類中方法互斥,類似與synchronized(this){}public synchronized void sub(int i) {//避免線程的假喚醒while(!jiaoti){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}for(int j=1;j<=10;j++){System.out.println("子線程:"+Thread.currentThread().getName()+"運行第"+i+"次,重復第"+j+"次");}jiaoti = false;this.notify();}//主線程運行的方法:同一個類中方法互斥,類似與synchronized(this){}public synchronized void main(int i){//避免線程的假喚醒while(jiaoti){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}for(int j=1;j<=10;j++){System.out.println("主線程:"+Thread.currentThread().getName()+"運行第"+i+"次,重復第"+j+"次");}jiaoti = true;this.notify();}
}

我們使用while循環來避免這種假喚醒的情況,當CPU任性的給與不該執行的線程、或者線程神經病的自己喚醒自己,我們可以使用while循環來避免上述情況。好了到此為止,代碼已經完全滿足我們的需求了。通過上面代碼的循序漸進,我們很容易理解線程間的同步與互斥技術。

總結:線程之間的制約關系?

?????? 當線程并發執行時,由于資源共享和線程協作,使用線程之間會存在以下兩種制約關系。

???? (1)間接相互制約。一個系統中的多個線程必然要共享某種系統資源,如共享CPU,共享I/O設備,所謂間接相互制約即源于這種資源共享,打印機就是最好的例子,線程A在使用打印機時,其它線程都要等待。

???? (2)直接相互制約。這種制約主要是因為線程之間的合作,如有線程A將計算結果提供給線程B作進一步處理,那么線程B在線程A將數據送達之前都將處于阻塞狀態。

?????? 間接相互制約可以稱為互斥,直接相互制約可以稱為同步,對于互斥可以這樣理解,線程A和線程B互斥訪問某個資源則它們之間就會產個順序問題——要么線程A等待線程B操作完畢,要么線程B等待線程操作完畢,這其實就是線程的同步了。因此同步包括互斥,互斥其實是一種特殊的同步

?

轉載于:https://www.cnblogs.com/aoshicangqiong/p/7707288.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/391044.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/391044.shtml
英文地址,請注明出處:http://en.pswp.cn/news/391044.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python數據結構之四——set(集合)

Python版本&#xff1a;3.6.2 操作系統&#xff1a;Windows 作者&#xff1a;SmallWZQ 經過幾天的回顧和學習&#xff0c;我終于把Python 3.x中的基礎知識介紹好啦。下面將要繼續什么呢&#xff1f;讓我想想先~~~嗯&#xff0c;還是先整理一下近期有關Python基礎知識的隨筆吧…

volatile關鍵字有什么用

問題&#xff1a;volatile關鍵字有什么用 在工作的時候&#xff0c;我碰到了volatile關鍵字。但是我不是非常了解它。我發現了這個解釋 這篇文章已經解釋了問題中的關鍵字的細節了&#xff0c;你們曾經用過它嗎或者見過正確使用這個關鍵字的樣例 回答 Java中同步的實現大多是…

knn 機器學習_機器學習:通過預測意大利葡萄酒的品種來觀察KNN的工作方式

knn 機器學習Introduction介紹 For this article, I’d like to introduce you to KNN with a practical example.對于本文&#xff0c;我想通過一個實際的例子向您介紹KNN。 I will consider one of my project that you can find in my GitHub profile. For this project, …

MMU內存管理單元(看書筆記)

http://note.youdao.com/noteshare?id8e12abd45bba955f73874450e5d62b5b&subD09C7B51049D4F88959668B60B1263B5 筆記放在了有道云上面了&#xff0c;不想再寫一遍了。 韋東山《嵌入式linux完全開發手冊》看書筆記轉載于:https://www.cnblogs.com/coversky/p/7709381.html

Java中如何讀取文件夾下的所有文件

問題&#xff1a;Java中如何讀取文件夾下的所有文件 Java里面是如何讀取一個文件夾下的所有文件的&#xff1f; 回答一 public void listFilesForFolder(final File folder) {for (final File fileEntry : folder.listFiles()) {if (fileEntry.isDirectory()) {listFilesFor…

github pages_如何使用GitHub Actions和Pages發布GitHub事件數據

github pagesTeams who work on GitHub rely on event data to collaborate. The data recorded as issues, pull requests, and comments become vital to understanding the project.在GitHub上工作的團隊依靠事件數據進行協作。 記錄為問題&#xff0c;請求和注釋的數據對于…

c# .Net 緩存 使用System.Runtime.Caching 做緩存 平滑過期,絕對過期

1 public class CacheHeloer2 {3 4 /// <summary>5 /// 默認緩存6 /// </summary>7 private static CacheHeloer Default { get { return new CacheHeloer(); } }8 9 /// <summary>10 /// 緩存初始化11 /// </summary>12 …

python 實現分步累加_Python網頁爬取分步指南

python 實現分步累加As data scientists, we are always on the look for new data and information to analyze and manipulate. One of the main approaches to find data right now is scraping the web for a particular inquiry.作為數據科學家&#xff0c;我們一直在尋找…

Java 到底有沒有析構函數呢?

Java 到底有沒有析構函數呢&#xff1f; ? ? Java 到底有沒有析構函數呢&#xff1f;我沒能找到任何有關找個的文檔。如果沒有的話&#xff0c;我要怎么樣才能達到一樣的效果&#xff1f; ? ? ? 為了使得我的問題更加具體&#xff0c;我寫了一個應用程序去處理數據并且說…

關于雙黑洞和引力波,LIGO科學家回答了這7個你可能會關心的問題

引力波的成功探測&#xff0c;就像雙黑洞的碰撞一樣&#xff0c;一石激起千層浪。 關于雙黑洞和引力波&#xff0c;LIGO科學家回答了這7個你可能會關心的問題 最近&#xff0c;引力波的成功探測&#xff0c;就像雙黑洞的碰撞一樣&#xff0c;一石激起千層浪。 大家興奮之余&am…

如何使用HTML,CSS和JavaScript構建技巧計算器

A Tip Calculator is a calculator that calculates a tip based on the percentage of the total bill.小費計算器是根據總賬單的百分比計算小費的計算器。 Lets build one now.讓我們現在建立一個。 第1步-HTML&#xff1a; (Step 1 - HTML:) We create a form in order to…

用于MLOps的MLflow簡介第1部分:Anaconda環境

在這三部分的博客中跟隨了演示之后&#xff0c;您將能夠&#xff1a; (After following along with the demos in this three part blog you will be able to:) Understand how you and your Data Science teams can improve your MLOps practices using MLflow 了解您和您的數…

[WCF] - 使用 [DataMember] 標記的數據契約需要聲明 Set 方法

WCF 數據結構中返回的只讀屬性 TotalCount 也需要聲明 Set 方法。 [DataContract]public class BookShelfDataModel{ public BookShelfDataModel() { BookList new List<BookDataModel>(); } [DataMember] public List<BookDataModel>…

sql注入語句示例大全_SQL Group By語句用示例語法解釋

sql注入語句示例大全GROUP BY gives us a way to combine rows and aggregate data.GROUP BY為我們提供了一種合并行和匯總數據的方法。 The data used is from the campaign contributions data we’ve been using in some of these guides.使用的數據來自我們在其中一些指南…

ConcurrentHashMap和Collections.synchronizedMap(Map)的區別是什么?

ConcurrentHashMap和Collections.synchronizedMap(Map)的區別是什么&#xff1f; 我有一個會被多個線程同時修改的Map 在Java的API里面&#xff0c;有3種不同的實現了同步的Map實現 HashtableCollections.synchronizedMap(Map)ConcurrentHashMap 據我所知&#xff0c;HashT…

pymc3 貝葉斯線性回歸_使用PyMC3估計的貝葉斯推理能力

pymc3 貝葉斯線性回歸內部AI (Inside AI) If you’ve steered clear of Bayesian regression because of its complexity, this article shows how to apply simple MCMC Bayesian Inference to linear data with outliers in Python, using linear regression and Gaussian ra…

Hadoop Streaming詳解

一&#xff1a; Hadoop Streaming詳解 1、Streaming的作用 Hadoop Streaming框架&#xff0c;最大的好處是&#xff0c;讓任何語言編寫的map, reduce程序能夠在hadoop集群上運行&#xff1b;map/reduce程序只要遵循從標準輸入stdin讀&#xff0c;寫出到標準輸出stdout即可 其次…

mongodb分布式集群搭建手記

一、架構簡介 目標 單機搭建mongodb分布式集群(副本集 分片集群)&#xff0c;演示mongodb分布式集群的安裝部署、簡單操作。 說明 在同一個vm啟動由兩個分片組成的分布式集群&#xff0c;每個分片都是一個PSS(Primary-Secondary-Secondary)模式的數據副本集&#xff1b; Confi…

歸約歸約沖突_JavaScript映射,歸約和過濾-帶有代碼示例的JS數組函數

歸約歸約沖突Map, reduce, and filter are all array methods in JavaScript. Each one will iterate over an array and perform a transformation or computation. Each will return a new array based on the result of the function. In this article, you will learn why …

為什么Java里面的靜態方法不能是抽象的

為什么Java里面的靜態方法不能是抽象的&#xff1f; 問題是為什么Java里面不能定義一個抽象的靜態方法&#xff1f;例如&#xff1a; abstract class foo {abstract void bar( ); // <-- this is okabstract static void bar2(); //<-- this isnt why? }回答一 因為抽…