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

歡迎訪問 生活随笔!

生活随笔

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

java

java 并发锁_Java并发教程–锁定:内在锁

發布時間:2023/12/3 java 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 并发锁_Java并发教程–锁定:内在锁 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

java 并發鎖

在之前的文章中,我們回顧了在不同線程之間共享數據的一些主要風險(例如原子性和可見性 )以及如何設計類以安全地共享( 線程安全的設計 )。 但是,在許多情況下,我們將需要共享可變數據,其中一些線程將寫入而其他線程將充當讀取器。 可能的情況是,只有一個域,與其他域無關,需要在不同線程之間共享。 在這種情況下,您可以使用原子變量。 對于更復雜的情況,您將需要同步。



1.咖啡店的例子

讓我們從一個簡單的示例開始,例如CoffeeStore 。 此類開設了一家商店,客戶可以在此購買咖啡。 客戶購買咖啡時,會增加一個計數器,以便跟蹤所售商品的數量。 商店還注冊誰是最后一個來商店的客戶。

public class CoffeeStore {private String lastClient;private int soldCoffees;private void someLongRunningProcess() throws InterruptedException {Thread.sleep(3000);}public void buyCoffee(String client) throws InterruptedException {someLongRunningProcess();lastClient = client;soldCoffees++;System.out.println(client + " bought some coffee");}public int countSoldCoffees() {return soldCoffees;}public String getLastClient() {return lastClient;} }

在以下程序中,四個客戶決定來商店購買咖啡:

public static void main(String[] args) throws InterruptedException {CoffeeStore store = new CoffeeStore();Thread t1 = new Thread(new Client(store, "Mike"));Thread t2 = new Thread(new Client(store, "John"));Thread t3 = new Thread(new Client(store, "Anna"));Thread t4 = new Thread(new Client(store, "Steve"));long startTime = System.currentTimeMillis();t1.start();t2.start();t3.start();t4.start();t1.join();t2.join();t3.join();t4.join();long totalTime = System.currentTimeMillis() - startTime;System.out.println("Sold coffee: " + store.countSoldCoffees());System.out.println("Last client: " + store.getLastClient());System.out.println("Total time: " + totalTime + " ms"); }private static class Client implements Runnable {private final String name;private final CoffeeStore store;public Client(CoffeeStore store, String name) {this.store = store;this.name = name;}@Overridepublic void run() {try {store.buyCoffee(name);} catch (InterruptedException e) {System.out.println("interrupted sale");}} }

主線程將使用Thread.join()等待所有四個客戶端線程完成。 一旦客戶離開,我們顯然應該算出我們商店中售出的四種咖啡,但是您可能會得到意想不到的結果,如上面的一種:

Mike bought some coffee Steve bought some coffee Anna bought some coffee John bought some coffee Sold coffee: 3 Last client: Anna Total time: 3001 ms

我們丟了一杯咖啡,最后一個客戶(John)也不是那個(Anna)。 原因是由于我們的代碼未同步,因此線程交錯。 我們的buyCoffee操作應該原子化。

2.同步如何工作

同步塊是由鎖保護的代碼區域。 當線程進入同步塊時,它需要獲取其鎖,并且一旦獲取,它就不會釋放它,直到退出該塊或引發異常。 這樣,當另一個線程嘗試進入同步塊時,只有所有者線程釋放它后,它才能獲取其鎖。 這是Java機制,可確保僅在給定時間在線程上執行同步的代碼塊,從而確保該塊內所有動作的原子性。

好的,所以您使用鎖來保護同步塊,但是什么是鎖? 答案是任何Java對象都可以用作鎖,稱為內在鎖。 現在,我們將看到使用同步時這些鎖的一些示例。

3.同步方法

同步方法由兩種類型的鎖保護:

  • 同步實例方法 :隱式鎖定為“ this”,這是用于調用該方法的對象。 此類的每個實例將使用自己的鎖。
  • 同步靜態方法 :鎖是Class對象。 此類的所有實例將使用相同的鎖。

和往常一樣,用一些代碼可以更好地看到這一點。

首先,我們將同步一個實例方法。 它的工作方式如下:我們有一個類的實例由兩個線程(線程1和線程2)共享,另一個實例由第三個線程(線程3)使用:

public class InstanceMethodExample {private static long startTime;public void start() throws InterruptedException {doSomeTask();}public synchronized void doSomeTask() throws InterruptedException {long currentTime = System.currentTimeMillis() - startTime;System.out.println(Thread.currentThread().getName() + " | Entering method. Current Time: " + currentTime + " ms");Thread.sleep(3000);System.out.println(Thread.currentThread().getName() + " | Exiting method");}public static void main(String[] args) {InstanceMethodExample instance1 = new InstanceMethodExample();Thread t1 = new Thread(new Worker(instance1), "Thread-1");Thread t2 = new Thread(new Worker(instance1), "Thread-2");Thread t3 = new Thread(new Worker(new InstanceMethodExample()), "Thread-3");startTime = System.currentTimeMillis();t1.start();t2.start();t3.start();}private static class Worker implements Runnable {private final InstanceMethodExample instance;public Worker(InstanceMethodExample instance) {this.instance = instance;}@Overridepublic void run() {try {instance.start();} catch (InterruptedException e) {System.out.println(Thread.currentThread().getName() + " interrupted");}}} }

由于doSomeTask方法是同步的,因此您希望在給定的時間只有一個線程將執行其代碼。 但這是錯誤的,因為它是一個實例方法。 不同的實例將使用不同的鎖,如輸出所示:

Thread-1 | Entering method. Current Time: 0 ms Thread-3 | Entering method. Current Time: 1 ms Thread-3 | Exiting method Thread-1 | Exiting method Thread-2 | Entering method. Current Time: 3001 ms Thread-2 | Exiting method

由于線程1和線程3使用不同的實例(因此使用了不同的鎖),因此它們都同時進入該塊。 另一方面,線程2使用與線程1相同的實例(和鎖)。 因此,它必須等到線程1釋放鎖。

現在,讓我們更改方法簽名并使用靜態方法。 除以下行外, StaticMethodExample具有相同的代碼:

public static synchronized void doSomeTask() throws InterruptedException {

如果執行main方法,將得到以下輸出:

Thread-1 | Entering method. Current Time: 0 ms Thread-1 | Exiting method Thread-3 | Entering method. Current Time: 3001 ms Thread-3 | Exiting method Thread-2 | Entering method. Current Time: 6001 ms Thread-2 | Exiting method

由于同步方法是靜態的,因此它由Class對象鎖保護。 盡管使用了不同的實例,所有線程仍需要獲取相同的鎖。 因此,任何線程都必須等待上一個線程釋放鎖。

4.回到咖啡店的例子

我現在修改了Coffee Store示例以使其方法同步。 結果如下:

public class SynchronizedCoffeeStore {private String lastClient;private int soldCoffees;private void someLongRunningProcess() throws InterruptedException {Thread.sleep(3000);}public synchronized void buyCoffee(String client) throws InterruptedException {someLongRunningProcess();lastClient = client;soldCoffees++;System.out.println(client + " bought some coffee");}public synchronized int countSoldCoffees() {return soldCoffees;}public synchronized String getLastClient() {return lastClient;} }

現在,如果我們執行該程序,我們將不會失去任何銷售:

Mike bought some coffee Steve bought some coffee Anna bought some coffee John bought some coffee Sold coffee: 4 Last client: John Total time: 12005 ms

完善! 好吧,真的是嗎? 現在程序的執行時間為12秒。 您肯定已經注意到在每次銷售期間都會執行someLongRunningProcess方法。 它可以是與銷售無關的操作,但是由于我們同步了整個方法,所以現在每個線程都必須等待它執行。 我們可以將這段代碼放在同步塊之外嗎? 當然! 下一節將介紹同步塊。

5.同步塊

上一節向我們展示了我們可能并不總是需要同步整個方法。 由于所有同步代碼都強制對所有線程執行進行序列化,因此我們應最小化同步塊的長度。 在我們的咖啡店示例中,我們可以省去長時間運行的過程。 在本節的示例中,我們將使用同步塊:

在SynchronizedBlockCoffeeStore中 ,我們修改buyCoffee方法,以將長時間運行的進程排除在同步塊之外:

public void buyCoffee(String client) throws InterruptedException {someLongRunningProcess();synchronized(this) {lastClient = client;soldCoffees++;System.out.println(client + " bought some coffee");} }public synchronized int countSoldCoffees() {return soldCoffees;}public synchronized String getLastClient() {return lastClient;}

在上一個同步塊中,我們將“ this”用作其鎖。 它與同步實例方法中的鎖相同。 當心使用另一個鎖,因為我們正在此類的其他方法( countSoldCoffees和getLastClient )中使用此鎖。

讓我們看看執行修改后的程序的結果:

Mike bought some coffee John bought some coffee Anna bought some coffee Steve bought some coffee Sold coffee: 4 Last client: Steve Total time: 3015 ms

在保持代碼同步的同時,我們大大減少了程序的時間。

6.使用私人鎖

上一節對實例對象使用了鎖定,但是您可以將任何對象用作其鎖定。 在本節中,我們將使用私人鎖,看看使用私人鎖會有什么風險。

在PrivateLockExample中 ,我們有一個由私有鎖(myLock)保護的同步塊:

public class PrivateLockExample {private Object myLock = new Object();public void executeTask() throws InterruptedException {synchronized(myLock) {System.out.println("executeTask - Entering...");Thread.sleep(3000);System.out.println("executeTask - Exiting...");}} }

如果一個線程進入executeTask方法將獲取myLock鎖。 在由相同的myLock鎖保護的此類中進入其他方法的任何其他線程,都必須等待才能獲取它。

但是,現在讓我們想象一下,有人想要擴展此類以添加自己的方法,并且由于需要使用相同的共享數據,因此這些方法也需要同步。 由于該鎖在基類中是私有的,因此擴展類將無法訪問它。 如果擴展類同步其方法,則將通過“ this”進行保護。 換句話說,它將使用另一個鎖。

MyPrivateLockExample擴展了先前的類,并添加了自己的同步方法executeAnotherTask :

public class MyPrivateLockExample extends PrivateLockExample {public synchronized void executeAnotherTask() throws InterruptedException {System.out.println("executeAnotherTask - Entering...");Thread.sleep(3000);System.out.println("executeAnotherTask - Exiting...");}public static void main(String[] args) {MyPrivateLockExample privateLock = new MyPrivateLockExample();Thread t1 = new Thread(new Worker1(privateLock));Thread t2 = new Thread(new Worker2(privateLock));t1.start();t2.start();}private static class Worker1 implements Runnable {private final MyPrivateLockExample privateLock;public Worker1(MyPrivateLockExample privateLock) {this.privateLock = privateLock;}@Overridepublic void run() {try {privateLock.executeTask();} catch (InterruptedException e) {e.printStackTrace();}}}private static class Worker2 implements Runnable {private final MyPrivateLockExample privateLock;public Worker2(MyPrivateLockExample privateLock) {this.privateLock = privateLock;}@Overridepublic void run() {try {privateLock.executeAnotherTask();} catch (InterruptedException e) {e.printStackTrace();}}} }

該程序使用兩個工作線程,分別執行executeTask和executeAnotherTask 。 輸出顯示線程如何交錯,因為它們沒有使用相同的鎖:

executeTask - Entering... executeAnotherTask - Entering... executeAnotherTask - Exiting... executeTask - Exiting...

7.結論

我們已經使用Java的內置鎖定機制回顧了內部鎖定的使用。 這里的主要關注點是需要使用共享數據的同步塊。 必須使用相同的鎖。

這篇文章是Java Concurrency Tutorial系列的一部分。 單擊此處閱讀本教程的其余部分。

  • 您可以在Github上找到源代碼。

翻譯自: https://www.javacodegeeks.com/2014/09/java-concurrency-tutorial-locking-intrinsic-locks.html

java 并發鎖

總結

以上是生活随笔為你收集整理的java 并发锁_Java并发教程–锁定:内在锁的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 日日夜夜精品免费 | 玉女心经是什么意思 | 阿v视频免费在线观看 | 色av色 | 国产猛男猛女超爽免费视频 | 一区二区三区波多野结衣 | 国产精品宾馆在线精品酒店 | 成人午夜影视在线观看 | 99国产成人精品 | 日韩精品一区二区三区视频在线观看 | 少妇高潮久久久 | 日本一区二区在线播放 | 69xxxx日本| 18被视频免费观看视频 | 国产不卡av在线播放 | 东京热加勒比无码少妇 | 超碰人人人人 | 久久久久婷 | 雪花飘电影在线观看免费高清 | 污视频网站免费看 | 亚洲精品福利在线 | 欧美巨乳在线观看 | 一级黄色大片网站 | 国产v亚洲v天堂无码久久久 | 久久白虎| 日本高清在线一区 | 欧美精品乱码久久久久久 | 欧美日韩国产综合在线 | 欧美最顶级a∨艳星 | 午夜肉伦伦 | 国产精品偷伦视频免费观看了 | 特黄aaaaaaaaa毛片免费视频 | 五月天中文字幕av | 亚洲色图欧美激情 | 草久久| 日韩激情视频在线观看 | 日本高潮网站 | 最新日韩一区 | 黄色大片免费看 | 亚洲精品66 | 一级特毛片 | 伦理片中文字幕 | 伊人视频在线观看 | 一本色道久久88 | 亚洲一区欧美二区 | 夜夜骑天天干 | 99热国内精品 | 91精品国产91综合久久蜜臀 | 夜夜骚视频 | 久久免费少妇高潮久久精品99 | 人人妻人人澡人人爽人人欧美一区 | 色福利hd写真video | 久久黄网| av爱爱爱 | a视频在线观看免费 | 粉嫩av一区二区三区免费观看 | 亚洲v| 欧美国产视频 | 九九一级片 | 精产国品一二三产品蜜桃 | 国产swag在线 | 成人国产三级 | 香蕉网在线观看 | 国产人妖视频 | 日韩黄色影院 | 色哟哟国产精品色哟哟 | 久久依人网 | 美女隐私免费网站 | 免费黄色一级视频 | 四虎网址在线 | 久久国产三级 | 成人动漫在线观看 | 女同性做爰全过程 | 亚洲成人黄色av | 日韩av一区二区三区四区 | 天堂一区在线 | 成人精品在线观看视频 | 国产一及毛片 | 成 年人 黄 色 片 | 动漫艳母在线观看 | 午夜影院在线播放 | 伊人中文字幕在线观看 | 黄色成人在线播放 | 久久人妻一区二区 | a亚洲精品 | 韩国一区二区在线观看 | m3u8成人免费视频 | 色操插 | 公肉吊粗大爽色翁浪妇视频 | 日日操狠狠操 | 久久国语对白 | 午夜看片在线观看 | 欧洲亚洲激情 | 99精品久久精品一区二区 | 男女激情四射网站 | 亚州黄色 | 精品无码一区二区三区在线 | 天天干在线播放 | 久久久国产精华液999999 |