線程同步丶java教程網,java線程同步的幾種方法

本文目錄一覽:

Java中線程怎麼同步

1、使用線程類自帶的join方法,將子線程加入到主線程,在子線程執行完之後,在執行主線程邏輯。

例如

[java] view plain copy  

public static void joinDemo()

throws InterruptedException

{

System.out.println(“=========Test with join=====”);

JoinWorker worker1 = new JoinWorker(“worker1”);

JoinWorker worker2 = new JoinWorker(“worker2”);

worker1.start();

worker2.start();

worker1.join();

worker2.join();

doSuperWork();

}

2、使用JDK的並發包中的CountDownLatch類, 使用CountDownLatch,每個線程調用其countDown方法使計數器-1,主線程調用await方法阻塞等待,直到CountDownLatch計數器為0時繼續執行,例如

首先,定義子線程

[java] view plain copy  

static class CountDownLatchWorker extends Thread

{

String workerName;

CountDownLatch latch;

public CountDownLatchWorker(String workerName, CountDownLatch latch)

{

this.workerName = workerName;

this.latch = latch;

}

public void run()

{

System.out.println(“Sub Worker ” + workerName + ” do work begin at “

+ sdf.format(new Date()));

new ThreadWaitDemo().doSomeWork();// 做實際工作

System.out.println(“Sub Worker ” + workerName + ” do work complete at “

+ sdf.format(new Date()));

latch.countDown();// 完成之後,計數器減一

}

}

主線程中調研await方法阻塞等待,直到所有線程完成

[html] view plain copy  

public static void countDownLatchDemo()

throws InterruptedException

{

System.out.println(“=========Test with CountDownLatch=====”);

CountDownLatch latch = new CountDownLatch(2);

CountDownLatchWorker worker1 = new CountDownLatchWorker(“worker1”, latch);

CountDownLatchWorker worker2 = new CountDownLatchWorker(“worker2”, latch);

worker1.start();

worker2.start();

//主線程阻塞等待

latch.await();

doSuperWork();

}

3、使用JDK並發包CyclicBarrier,CyclicBarrier類似於CountDownLatch也是個計數器, 不同的是CyclicBarrier的await()方法沒被調用一次,計數便會減少1,並阻塞住當前線程。當計數減至0時,阻塞解除,所有在此 CyclicBarrier 上面阻塞的線程開始運行。 在這之後,如果再次調用 await()方法,計數就又會變成 N-1,新一輪重新開始CyclicBarrier初始時還可帶一個Runnable的參數,此Runnable任務在CyclicBarrier的數目達到後,所有其它線程被喚醒前被執行。

示例如下

[java] view plain copy  

public static void cyclicBarrierDemo()

throws InterruptedException, BrokenBarrierException

{

System.out.println(“=========Test with CyclicBarrier=====”);

CyclicBarrier cb = new CyclicBarrier(2, new Runnable()

{

// 將主線程業務放到CyclicBarrier構造方法中,所有線程都到達Barrier時執行

@SuppressWarnings(“static-access”)

public void run()

{

new ThreadWaitDemo().doSuperWork();

}

});// 設定需要等待兩個線程

ExecutorService executor = Executors.newFixedThreadPool(2);

CyclicBarrierWorker worker1 = new CyclicBarrierWorker(“worker1”, cb);

CyclicBarrierWorker worker2 = new CyclicBarrierWorker(“worker2”, cb);

executor.execute(worker1);

executor.execute(worker2);

executor.shutdown();

}

4、使用JDK並發包中的Executors框架,ExecutorService的的invokeAll方法調研callable集合,批量執行多個線程,在invokeAll方法結束之後,再執行主線程其他業務邏輯

示例如下

[java] view plain copy  

public static void callableDemo()

throws InterruptedException

{

System.out.println(“=========Test with Callable=====”);

ListCallableInteger callList = new ArrayListCallableInteger();

ExecutorService exec = Executors.newFixedThreadPool(2);

// 採用匿名內部類實現

callList.add(new CallableInteger()

{

public Integer call()

throws Exception

{

System.out.println(“Sub Worker worker1 do work begin at ” + sdf.format(new Date()));

new ThreadWaitDemo().doSomeWork();// 做實際工作

System.out.println(“Sub Worker worker1 do work complete at “

+ sdf.format(new Date()));

return 0;

}

});

callList.add(new CallableInteger()

{

public Integer call()

throws Exception

{

System.out.println(“Sub Worker worker2 do work begin at ” + sdf.format(new Date()));

new ThreadWaitDemo().doSomeWork();// 做實際工作

System.out.println(“Sub Worker worker2 do work complete at “

+ sdf.format(new Date()));

return 0;

}

});

exec.invokeAll(callList);

exec.shutdown();

doSuperWork();

}

5、這種過於噁心,只簡單說一下方法,主線程創建一個線程List,將每個子線程保存到列表中,然後定期輪詢列表中子線程狀態,當所有線程都完成之後,再執行主線程邏輯

簡單寫出線程同步的方法(java)

/**

* Java線程:線程的同步

*

* @author leizhimin 2009-11-4 11:23:32

*/

public class Test {

public static void main(String[] args) {

User u = new User(“張三”, 100);

MyThread t1 = new MyThread(“線程A”, u, 20);

MyThread t2 = new MyThread(“線程B”, u, -60);

MyThread t3 = new MyThread(“線程C”, u, -80);

MyThread t4 = new MyThread(“線程D”, u, -30);

MyThread t5 = new MyThread(“線程E”, u, 32);

MyThread t6 = new MyThread(“線程F”, u, 21);

t1.start();

t2.start();

t3.start();

t4.start();

t5.start();

t6.start();

}

}

class MyThread extends Thread {

private User u;

private int y = 0;

MyThread(String name, User u, int y) {

super(name);

this.u = u;

this.y = y;

}

public void run() {

u.oper(y);

}

}

class User {

private String code;

private int cash;

User(String code, int cash) {

this.code = code;

this.cash = cash;

}

public String getCode() {

return code;

}

public void setCode(String code) {

this.code = code;

}

/**

* 業務方法

* @param x 添加x萬元

*/

public synchronized void oper(int x) {

try {

Thread.sleep(10L);

this.cash += x;

System.out.println(Thread.currentThread().getName() + “運行結束,增加“” + x + “”,當前用戶賬戶餘額為:” + cash);

Thread.sleep(10L);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

@Override

public String toString() {

return “User{” +

“code='” + code + ‘\” +

“, cash=” + cash + ‘}’;

}

}

輸出結果:線程A運行結束,增加“20”,當前用戶賬戶餘額為:120

線程F運行結束,增加”21″,當前用戶賬戶餘額為:141

線程E運行結束,增加”32″,當前用戶賬戶餘額為:173

線程C運行結束,增加”-80″,當前用戶賬戶餘額為:93

線程B運行結束,增加”-60″,當前用戶賬戶餘額為:33

線程D運行結束,增加”-30″,當前用戶賬戶餘額為:3

Process finished with exit code 0反面教材,不同步的情況,也就是去掉oper(int x)方法的synchronized修飾符,然後運行程序,結果如下:線程A運行結束,增加”20″,當前用戶賬戶餘額為:61

線程D運行結束,增加”-30″,當前用戶賬戶餘額為:63

線程B運行結束,增加”-60″,當前用戶賬戶餘額為:3

線程F運行結束,增加”21″,當前用戶賬戶餘額為:61

線程E運行結束,增加”32″,當前用戶賬戶餘額為:93

線程C運行結束,增加”-80″,當前用戶賬戶餘額為:61

Process finished with exit code 0很顯然,上面的結果是錯誤的,導致錯誤的原因是多個線程並發訪問了競爭資源u,並對u的屬性做了改動。可見同步的重要性。注意:通過前文可知,線程退出同步方法時將釋放掉方法所屬對象的鎖,但還應該注意的是,同步方法中還可以使用特定的方法對線程進行調度。這些方法來自於java.lang.Object類。

void notify()

喚醒在此對象監視器上等待的單個線程。

void notifyAll()

喚醒在此對象監視器上等待的所有線程。

void wait()

導致當前的線程等待,直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法。

void wait(long timeout)

導致當前的線程等待,直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量。

void wait(long timeout, int nanos)

導致當前的線程等待,直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其他某個線程中斷當前線程,或者已超過某個實際時間量。

Java如何實現多線程同步?

//解決方案-1 設置3把鎖, 然後把鎖們應用到所有線程中 (涉及到synchronized wait notify等, 嫌麻煩. 略)

解決方案-2 設置3個全局共享的信號標記(信號燈) + 3子線程分別佔用標記1 2 3

+ 主線程輪詢/等待

(簡潔明快 推薦)

//解決方案-2 實現如下:

static boolean t1_done = false;

static boolean t2_done = false;

static boolean t3_done = false;

//t1——run() { ………… ; t1_done = true; }

//t2、 3: 同理,略

main () { ………….;

啟動t1;

啟動t2;

啟動t3;

//輪詢 or 等待

while ( true )

if ( t1_done t2_done t3_done) break;

else

Thread.yield () ;

// 或 Thread.sleep(xxxx) —-若子線程運行超過100ms以上,應予考慮

//輪詢結束,主線程繼續工作

} //main END

have fun

Java線程同步的方法

等待喚醒機制

wait():讓線程等待。將線程存儲到一個線程池中。

notify():喚醒被等待的線程。通常都喚醒線程池中的第一個。讓被喚醒的線程處於臨時阻塞狀態。

notifyAll(): 喚醒所有的等待線程。將線程池中的所有線程都喚醒,讓它們從凍結狀體轉到臨時阻塞狀態.

這三個方法用於操作線程,可是定義在了Object類中,為什麼呢?

因為,這三個方法在使用時,都需要定義在同步中,要明確這些方法所操作的線程所屬於鎖。

簡單說。在A鎖被wait的線程,只能被A鎖的notify方法喚醒。

所以必須要表示wait notify方法所屬的鎖對象,而鎖對象可以是任意的對象。

可以被任意的對象調用的方法肯定定義在Object類中。

注意:等待喚醒機制,通常都用在同步中,因為需要鎖的支持。

而且必須要明確wait notify 所作用的鎖對象。

JDK1.5後的鎖

在jdk1.5版本之後,

出現了一些新的特性,將原理的線程進行了改良。

在java.util.concurrent.locks包中提供了一個接口Lock。替代了synchronized。

synchronized。使用的是鎖操作是隱式的。

Lock接口,使用的鎖操作是顯示的。

由兩個方法來完成:

lock():獲取鎖。

unlock():釋放鎖。

還有一個對象,Condition.

該對象的出現替代了Object中的wait notify notifyAll這些操作監視器的方法。

替代後的方式:await signal signalAll.

java中線程同步的幾種方法

線程同步主要有以下種方法(示例中是實現計數的功能):

1、同步方法,即使用synchronized關鍵字修飾方法,例如:

public synchronized void add(int c){…}

2、同步代碼塊,即有synchronized關鍵字修飾的語句塊,例如:

public void addAndGet(int c){

    synchronized(this){

      count += c;

    }

}

3、使用特殊域變量(volatile)實現線程同步,該方法不能保證絕對的同步。

例如:private volatile int count = 0;

4、使用鎖實現線程同步,例如:

private Lock lock = new ReentrantLock();

  public void add(int c) {  

        lock.lock();//上鎖  

        try{  

            count += c;  

        }finally{  

            lock.unlock();//解鎖  

        }  

    }

5、使用原子變量實現線程同步,在java的util.concurrent.atomic包中提供了創建了原子類型變量的工具類,例如:

private AtomicInteger count= new AtomicInteger(1);

public void add(int c) {

    count.addAndGet(c);

}

6、使用局部變量實現線程同步,如果使用ThreadLocal管理變量,則每一個使用該變量的線程都獲得該變量的副本, 副本之間相互獨立,這樣每一個線程都可以隨意修改自己的變量副本,而不會對其他線程產生影響。

ThreadLocal 類的常用方法

new ThreadLocalT() : 創建一個線程本地變量

get() : 返回此線程局部變量的當前線程副本中的值

initialValue() : 返回此線程局部變量的當前線程的”初始值”

set(T value) : 將此線程局部變量的當前線程副本中的值設置為value

示例代碼:

private static ThreadLocalInteger count= new ThreadLocalInteger(){

          @Override

          protected Integer initialValue(){ 

              return 1;

             }

     };            

 

public void add(int c){

                count.set(count.get() + c);

    }

7、使用阻塞隊列實現,例如LinkedBlockingQueue,具體使用可百度LinkedBlockingQueue的用法或查看java文檔。

原創文章,作者:MRBT,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/137885.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
MRBT的頭像MRBT
上一篇 2024-10-04 00:18
下一篇 2024-10-04 00:18

相關推薦

  • Java JsonPath 效率優化指南

    本篇文章將深入探討Java JsonPath的效率問題,並提供一些優化方案。 一、JsonPath 簡介 JsonPath是一個可用於從JSON數據中獲取信息的庫。它提供了一種DS…

    編程 2025-04-29
  • java client.getacsresponse 編譯報錯解決方法

    java client.getacsresponse 編譯報錯是Java編程過程中常見的錯誤,常見的原因是代碼的語法錯誤、類庫依賴問題和編譯環境的配置問題。下面將從多個方面進行分析…

    編程 2025-04-29
  • Java騰訊雲音視頻對接

    本文旨在從多個方面詳細闡述Java騰訊雲音視頻對接,提供完整的代碼示例。 一、騰訊雲音視頻介紹 騰訊雲音視頻服務(Cloud Tencent Real-Time Communica…

    編程 2025-04-29
  • Java Bean加載過程

    Java Bean加載過程涉及到類加載器、反射機制和Java虛擬機的執行過程。在本文中,將從這三個方面詳細闡述Java Bean加載的過程。 一、類加載器 類加載器是Java虛擬機…

    編程 2025-04-29
  • MQTT使用教程

    MQTT是一種輕量級的消息傳輸協議,適用於物聯網領域中的設備與雲端、設備與設備之間的數據傳輸。本文將介紹使用MQTT實現設備與雲端數據傳輸的方法和注意事項。 一、準備工作 在使用M…

    編程 2025-04-29
  • Java Milvus SearchParam withoutFields用法介紹

    本文將詳細介紹Java Milvus SearchParam withoutFields的相關知識和用法。 一、什麼是Java Milvus SearchParam without…

    編程 2025-04-29
  • Python3.6.5下載安裝教程

    Python是一種面向對象、解釋型計算機程序語言。它是一門動態語言,因為它不會對程序員提前聲明變量類型,而是在變量第一次賦值時自動識別該變量的類型。 Python3.6.5是Pyt…

    編程 2025-04-29
  • Deepin系統分區設置教程

    本教程將會詳細介紹Deepin系統如何進行分區設置,分享多種方式讓您了解如何規劃您的硬盤。 一、分區的基本知識 在進行Deepin系統分區設置之前,我們需要了解一些基本分區概念。 …

    編程 2025-04-29
  • Java 8中某一周的周一

    Java 8是Java語言中的一個版本,於2014年3月18日發布。本文將從多個方面對Java 8中某一周的周一進行詳細的闡述。 一、數組處理 Java 8新特性之一是Stream…

    編程 2025-04-29
  • Java判斷字符串是否存在多個

    本文將從以下幾個方面詳細闡述如何使用Java判斷一個字符串中是否存在多個指定字符: 一、字符串遍歷 字符串是Java編程中非常重要的一種數據類型。要判斷字符串中是否存在多個指定字符…

    編程 2025-04-29

發表回復

登錄後才能評論