Java 線程安全

線程安全

  • 線程安全概念:當多個線程訪問某一個類(對象或方法)時,這個類始終都能表現出正確的行為,那么這個類(對象或方法)就是線程安全的。
  • synchronized:可以在任意對象及方法上加鎖,而加鎖的這段代碼稱為“互斥區”或“臨界區”。
  • 當多個線程訪問myThread的run方法時,以排隊的方式進行處理(這里排對是按照CPU分配的先后順序而定的),一個線程想要執行synchronized修飾的方法里的代碼,首先是嘗試獲得鎖,如果拿到鎖,執行synchronized代碼體內容;拿不到鎖,這個線程就會不斷的嘗試獲得這把鎖,直到拿到為止,而且是多個線程同時去競爭這把鎖。(也就是會有鎖競爭的問題)

線程不安全

package com.example.core.safely;public class MyThread extends Thread{private int count = 5;public void run(){count--;System.out.println(this.currentThread().getName() + "count = "+count);}public static void main(String[] args) {MyThread my = new MyThread();Thread t1 = new Thread(my,"t1");Thread t2 = new Thread(my,"t2");Thread t3 = new Thread(my,"t3");Thread t4 = new Thread(my,"t4");Thread t5 = new Thread(my,"t5");t1.start();t2.start();t3.start();t4.start();t5.start();}
}

線程安全 -> 添加synchronized

  • synchronized 同步的概念就是共享,我們要牢牢記住"共享"這倆個字,如果不是共享的資源,就沒有必要進行同步。
  • 異步:asynchronized 異步的概念就是獨立,相互之間不受到任何制約。就好像我們學習http的時候,在頁面發起的Ajax請求,我們還可以繼續瀏覽或操作頁面的內容,二者之間沒有任何關系
  • 同步的目的就是為了線程安全,其實對于線程安全來說,需要滿足倆個特性: 原子性(同步) 可見性?? ?
package com.example.core.safely;public class MyThread extends Thread{private int count = 5;public synchronized void run(){count--;System.out.println(this.currentThread().getName() + "count = "+count);}public static void main(String[] args) {MyThread my = new MyThread();Thread t1 = new Thread(my,"t1");Thread t2 = new Thread(my,"t2");Thread t3 = new Thread(my,"t3");Thread t4 = new Thread(my,"t4");Thread t5 = new Thread(my,"t5");t1.start();t2.start();t3.start();t4.start();t5.start();}
}

線程之間的通信

  • 線程通信概念:線程是操作系統中獨立的個體,但這些個體如果不經過特殊的處理就不能成為一個整體,線程間的通信就成為整體的必用方式之一。當線程存在通信指揮,系統間的交互性會更強大,在提高CPU利用率的同時還會使開發人員對線程任務在處理的過程中進行有效的把控與監督
  • 使用wait / notify 方法實現線程間的通信。(注意這兩個方法都是object的類的方法,換句話說java為所有的對象都提供了這兩個方法) wait 和 notify 必須配合 synchronized 關鍵字使用 wait方法釋放鎖notify方法不釋放鎖

ThreadLocal

  • 線程局部變量,是一種多線程間并發訪問變量的解決方案。與其synchronized等加鎖的方式不同,ThreadLocal完全不提供鎖,而使用以空間換時間的手段,為每個線程提供變量的獨立副本,以保障線程安全
  • 從性能上說,ThreadLocal不具有絕對的優勢,在并發不是很高的時候,加鎖的性能會更好,但作為一套與鎖完全無關的線程安全解決方案,在高并發量或者競爭激烈的場景,使用ThreadLocal可以在一定程度上減少鎖競爭
package com.example.core.safely;public class UseThreadLocal {public static ThreadLocal<String> threadLocal = new ThreadLocal<>();public void setThreadLocal(String value){threadLocal.set(value);}public String getThreadLocal(){return threadLocal.get();}public static void main(String[] args) {UseThreadLocal utl = new UseThreadLocal();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {utl.setThreadLocal("張三");System.err.println("當前t1:"+utl.getThreadLocal());}},"t1");Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {utl.setThreadLocal("李四");System.err.println("當前t2:"+utl.getThreadLocal());}},"t2");try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}t1.start();t2.start();System.out.println("當前值"+utl.getThreadLocal());}
}

問題

  • 如題,有兩個線程A、B,A線程向一個集合(List<String>) 里面依次添加元素“abc”字符串, 一共添加十次,當添加到第五次的時候,希望B線程能夠收到A線程的通知,然后B線程執行相關的業務操作,我們應該如何進行設計?

1,使用CountDownLatch

  • latch.countDown();//喚醒通知
  • latch.await();//阻塞
    
package com.example.core.safely;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;public class ListAdd2 {// 1 定義的承裝字符串的容器private static List list = new ArrayList();	// 2 追加方法public void add(){list.add("bfxy");}public int size(){return list.size();}public static void main(String[] args) {final ListAdd2 list1 = new ListAdd2();final CountDownLatch latch = new CountDownLatch(1);//CountDownLatch讓一個線程阻塞,另一個線程運行,(1)是通知的個數// 線程AThread A = new Thread(new Runnable() {@Overridepublic void run() {try {for(int i = 0; i <10; i++){list1.add();System.out.println("當前線程:" + Thread.currentThread().getName() + ", 添加了一個元素..");Thread.sleep(500);if(list.size() == 5) {System.err.println("已經發出了喚醒通知!");latch.countDown();//喚醒通知}}						} catch (InterruptedException e) {e.printStackTrace();}}}, "A");// 線程BThread B = new Thread(new Runnable() {@Overridepublic void run() {while(true){if(list1.size() != 5) {try {latch.await();//阻塞} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("當前線程收到通知:" + Thread.currentThread().getName() + " list size = 5 線程停止..");throw new RuntimeException();}}}, "B");	B.start();try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}A.start();}}

2,使用volalite關鍵字

package com.example.core.safely;import java.util.ArrayList;
import java.util.List;public class ListAdd3 {// 1 定義的承裝字符串的容器private volatile static List list = new ArrayList();	// 2 追加方法public void add(){list.add("bfxy");}public int size(){return list.size();}public static void main(String[] args) {final ListAdd3 list1 = new ListAdd3();// 線程AThread A = new Thread(new Runnable() {@Overridepublic void run() {try {for(int i = 0; i <10; i++){list1.add();System.out.println("當前線程:" + Thread.currentThread().getName() + ", 添加了一個元素..");Thread.sleep(500);}						} catch (InterruptedException e) {e.printStackTrace();}}}, "A");// 線程BThread B = new Thread(new Runnable() {@Overridepublic void run() {while(true){if(list1.size() == 5){System.out.println("當前線程收到通知:" + Thread.currentThread().getName() + " list size = 5 線程停止..");throw new RuntimeException();}}}}, "B");	B.start();try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}A.start();}}

3,使用synchronized配合使用wait和notify

package com.example.core.safely;import java.util.ArrayList;
import java.util.List;public class ListAdd1 {// 1 定義的承裝字符串的容器private static List list = new ArrayList();	// 2 追加方法public void add(){list.add("bfxy");}public int size(){return list.size();}public static void main(String[] args) {final ListAdd1 list1 = new ListAdd1();final Object lock = new Object();// 線程AThread A = new Thread(new Runnable() {@Overridepublic void run() {try {synchronized (lock) {for(int i = 0; i <10; i++){list1.add();System.out.println("當前線程:" + Thread.currentThread().getName() + ", 添加了一個元素..");Thread.sleep(500);if(list.size() == 5) {System.err.println("已經發出了喚醒通知!");lock.notify();}}						}} catch (InterruptedException e) {e.printStackTrace();}}}, "A");// 線程BThread B = new Thread(new Runnable() {@Overridepublic void run() {while(true){synchronized (lock) {if(list1.size() != 5) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}}//if(list1.size() == 5){System.out.println("當前線程收到通知:" + Thread.currentThread().getName() + " list size = 5 線程停止..");throw new RuntimeException();//}}}}, "B");	B.start();try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}A.start();}}

?

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

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

相關文章

開發者應該了解的API技術清單!

摘要&#xff1a;有人說&#xff0c;有API的地方就有App&#xff0c;借助這些API開發者輕松構建出一款應用&#xff0c;極大地提高開發效率和開發質量。文中整理了一份API服務清單&#xff0c;內容涵蓋&#xff1a;監控/調試、 CDN 、數據庫、儀表盤、支付、通信等方面&#xf…

提高程序員職場價值的10大技巧

如果你已經是個很牛叉的程序員&#xff0c;但是依然覺得覺得還不夠的話&#xff0c;歡迎閱讀此文。本文旨在幫助各位更上一層樓。 你是不是覺得自己已經掌握了所有的編程技巧&#xff1f;別太自以為是了&#xff01; 會寫代碼的確很重要&#xff0c;但是要拿到更好薪水&#…

google python的風格規范

點擊鏈接&#xff0c;查看內容

IT人應當知道的10個行業小內幕

如果你打算從事IT行業或剛進入這個行業&#xff0c;也許本文下面的小內幕會嚇到你&#xff0c;因為這些事平常都不會公開討論的。如果你是IT資深人士&#xff0c;或許你已經遇到其中的大部分了。如果你愿意&#xff0c;請一起來參與討論吧。 這些內幕大多數是針對網絡管理員、…

Volatile原子性一致性JVM指令重排

概念 Volatile概念&#xff1a;Volatile關鍵字的主要作用是使變量在多個線程間可見。作用&#xff1a; 在多線程間可以進行變量的變更&#xff0c;使得線程間進行數據的共享可見 阻止指令重排序&#xff0c;happens-before package com.example.core.cas;import com.example.c…

python修改文件內容,不需要read,write多個動作。

python 要修改文件內容&#xff0c;常用 是先read&#xff0c;后write &#xff0c; 再 rename&#xff0c;很不爽。 比如&#xff1a;需要 把 yuv_dir "../HD/" # "H:/HD_Master/1080i25/" 改為 yuv_dir "C:/HD/" # "H:…

Atomic系列類

Atomic系列類別 Atomic系列類封裝了一系列的基礎類型和對象操作&#xff0c;其主要目的就是為了實現原子性&#xff0c;主要核心類如下 AtomicIntegerAtomicLongAtomicBooleanAtomicIntegerArrayAtomicLongArrayAtomicReference 原子性的引用對象在對Atomic類操作的時候&…

python 系統學習筆記(十二)---os os.path os.walk

得到當前工作目錄&#xff0c;即當前 Python腳本工作的目錄路徑: os.getcwd() 返回指定目錄下的所有文件和目錄名:os.listdir()函數用來刪除一個文件:os.remove()刪除多個目錄&#xff1a;os.removedirs&#xff08;r“c&#xff1a;\python”&#xff09;檢驗給出的路徑是否是…

Java JUC工具類--CountDownLatch

CountDownLatch&#xff1a;用于監聽某些初始化操作&#xff0c;并且線程進行阻塞&#xff0c;等初始化執行完畢后&#xff0c;通知主線程繼續工作執行 package com.example.core.juc;import java.util.concurrent.CountDownLatch;public class UseCountDownLatch {public stat…

Java JUC工具類--CyclicBarrier

CyclicBarrier&#xff1a;柵欄的概念&#xff0c;多線程的進行阻塞&#xff0c;等待某一個臨界值條件滿足后&#xff0c;同時執行 類比&#xff1a;每個線程代表一個跑步運動員&#xff0c;當運動員都準備好后&#xff0c;才一起出發&#xff0c;只要有一個人沒有準備好&#…

人生感悟:人生像吃自助餐

問我怎樣管理欲望&#xff0c;過簡單生活?我的答案是&#xff1a;你要先學會品味人生&#xff0c;品味的同義詞&#xff0c;就叫做體悟內涵。 人為什么有這么多欲望?其實&#xff0c;我們每個人在一個社會&#xff0c;就像進入一個自助餐(buffet)店&#xff0c;食物非常的多…

Java JUC工具類--Future

Future模式&#xff0c;也是非常經典的設計模式&#xff0c;這種模式主要就利用空間換時間的概念&#xff0c;也就是說異步執行&#xff08;需要開啟一個新的線程&#xff09;在互聯網高并發的應用服務中&#xff0c;我們隨處可見這種理念和代碼&#xff0c;主要就是使用了這種…

職場與生活 八條原則 讓你不再浪費時間和提高效率

Heidi Roizen女士一度是硅谷人人爭相學習的典范。她曾創辦自己的公司并管理了14年之久。后來&#xff0c;她擔任蘋果公司主管開發者關系的高級副總裁。現在&#xff0c;她是DFJ Venture的一位風投家&#xff0c;她還在斯坦福主講一門名叫??“企業家精神??”的課程。她幾乎認…

Java JUC工具類--Exchanger

Exchanger Exchanger用于進行線程間的數據交換&#xff0c;它提供一個同步點&#xff0c;在這個同步點&#xff0c;兩個線程可以交換彼此的數據兩個線程通過exchange方法交換數據&#xff0c;如果一個線程先執行exchange方法&#xff0c;它會一直等待第二個線程也執行exchang…

爸爸的素質決定孩子飛多高,爸爸們請反復看!!!

好父親等于200個好老師&#xff0c;當爹的都好好看看&#xff0c;以后孩子不給力別怨別人! 孩子是父親的影子&#xff0c;希望每個閱讀完全文的父親&#xff0c;都能成為一個好父親。 NO.1爸爸是孩子最好的老師 爸爸的素質有多高&#xff0c;孩子就能飛多高 用理性的父愛幫…

Java JUC工具類--ForkJoin

ForkJoin Fork/Join框架是JAVA7提供的一個用于并行執行任務的框架&#xff0c;是一個把大任務分割成若干個小任務&#xff0c;最終匯總每個小任務結果后得到大任務結果的框架Fork/Join中兩個重要的類 ForkJoinTask&#xff1a;使用該框架&#xff0c;需要創建一個ForkJoin任務…

修復bug的12個關鍵步驟

要多少時間才能修復bug&#xff0c;事先是很難知道的&#xff0c;特別是如果你和這些代碼還素不相識的話&#xff0c;情況就更加撲朔迷離了。James Shore在《The Art of Agile 》一書中&#xff0c;明確指出要想修復問題得先知道問題的所在。而我們之所以無法準確估計時間是因為…

Java JUC工具類--Master-Worker

Master-Worker Master-Worker模式是常用的并行計算模式。它的核心思想是系統由兩類進程協作工作&#xff1a;Master進程和Worker進程Master負責接收和分配任務&#xff0c;Worker負責處理子任務當各個Worker子進程處理完成后&#xff0c;會將結果返回給Master&#xff0c;由Ma…

身體打來的電話,你一定要接!

心臟有問題時。左邊手臂會酸、麻、痛。肝臟有問題時。小腿晚上睡覺時容易抽筋。腎臟出現問題時。聲音就會出不來&#xff0c;就會沙啞。脾胃出現問題時。偏頭痛。附&#xff1a;五臟排毒最簡單有效的方法 一、心臟有問題時 1。呼吸會不順暢&#xff0c;胸口會悶也會刺痛&…