深入探究一下Java中不同的線程間數據通信方式
1、多線程如何共享數據
多線程數據共享可以分為以下2種情況,線程實現代碼相同及線程實現代碼不同。
線程實現代碼相同
即runnable中的代碼一致,這樣可以直接在實現中定義成員變量直接共享
public class SharedSameRunnableDemo { public static void main(String[] args) { Runnable runnable = new MySameRunnable(); Thread thread1 = new Thread(runnable); Thread thread2 = new Thread(runnable); thread1.start(); thread2.start(); } private static class MySameRunnable implements Runnable { private int sharedData = 0; @Override public synchronized void run() { for (int i = 0; i < 5; i++) { sharedData++; System.out.println("Thread: " + Thread.currentThread().getName() + ", sharedData: " + sharedData); } } } }
在上面的示例中,我們定義瞭一個名為 MySameRunnable 的內部類它的共享變量是sharedData,它實現瞭Runnable 接口,並重寫瞭 run() 方法。在 run() 方法中,我們使用瞭 synchronized 關鍵字來保證線程安全。然後在main() 方法中,我們創建瞭一個 MySameRunnable 實例 runnable,並將其傳入兩個不同的線程對象中。最後啟動這兩個線程。由於這兩個線程共享同一個 MySameRunnable 實例,因此它們執行的代碼是相同的,並且可以訪問和修改sharedData 變量。通過這種方式,就可以實現多個線程共享數據,並確保線程安全。
線程實現代碼不相同
即runnable中的代碼不一致,MyRunnable1 MyRunnable2,利用一個對象SharedData,把runnable中的方法封裝到這個對象中去,數據也在這個對象中。如果多個線程實現的代碼不同,並且需要共享變量,可以使用一個單獨的類來存儲這些共享變量,並將它傳遞給所有的 Runnable 實例。以下是一個簡單的示例代碼:
public class SharedDifferentRauuableDemo { public static void main(String[] args) { SharedData sharedData = new SharedData(); Thread thread1 = new Thread(new MyRunnable1(sharedData)); Thread thread2 = new Thread(new MyRunnable2(sharedData)); thread1.start(); thread2.start(); } private static class SharedData { private int data = 0; public synchronized void increment() { data++; System.out.println("IncrementThread: " + data); } public synchronized void decrement() { data--; System.out.println("DecrementThread: " + data); } } private static class MyRunnable1 implements Runnable { private SharedData sharedData; public MyRunnable1(SharedData sharedData) { this.sharedData = sharedData; } @Override public void run() { for (int i = 0; i < 5; i++) { sharedData.increment(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } private static class MyRunnable2 implements Runnable { private SharedData sharedData; public MyRunnable2(SharedData sharedData) { this.sharedData = sharedData; } @Override public void run() { for (int i = 0; i < 5; i++) { sharedData.decrement(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
在上面的示例中,我們定義瞭一個 SharedData 類來存儲共享變量 data。這個類包含兩個同步方法 increment() 和 decrement(),用於增加和減少 data 的值,並輸出當前的值。然後我們創建瞭兩個 MyRunnable1 和 MyRunnable2 實例,它們分別傳遞瞭相同的 SharedData 對象。在 run() 方法中,它們調用 SharedData 對象的 increment() 和 decrement() 方法來進行數據修改,並使用 Thread.sleep() 方法讓線程休眠一段時間。
通過這種方式,就可以實現多個線程共享數據,並確保線程安全。
2、子線程如何繼承父線程數據
通過 InteritableThreadLocal實現共享
public class InheritableThreadLocalDemo { private static final InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<>(); public static void main(String[] args) { inheritableThreadLocal.set("Hello, World!"); Thread parentThread = new Thread(() -> { System.out.println("Parent Thread: " + inheritableThreadLocal.get()); inheritableThreadLocal.set("Hello from Parent Thread!"); Thread childThread = new Thread(() -> { System.out.println("Child Thread: " + inheritableThreadLocal.get()); }); childThread.start(); try { childThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Parent Thread: " + inheritableThreadLocal.get()); }); parentThread.start(); try { parentThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Main Thread: " + inheritableThreadLocal.get()); inheritableThreadLocal.remove(); } }
在上面的示例中,我們創建瞭一個 InheritableThreadLocal 對象,並將其設置為“Hello, World!”。然後,我們創建瞭一個名為“parentThread”的線程,並在其中輸出 inheritableThreadLocal 的值。接下來,我們在父線程中將 inheritableThreadLocal 的值設置為“Hello from Parent Thread!”,並創建瞭一個名為“childThread”的線程,在其中輸出 inheritableThreadLocal 的值。
註意:由於 InheritableThreadLocal 是可繼承的,所以在子線程中也能夠獲取到父線程中設置的值。因此,當我們在子線程中輸出 inheritableThreadLocal 的值時,我們將看到輸出“Hello from Parent Thread!”。
最後,我們分別在父線程、子線程和主線程中輸出 inheritableThreadLocal 的值。由於我們在每個線程中都設置瞭 inheritableThreadLocal 的值,所以每個線程都將輸出不同的值。
請註意,在程序的結尾處,我們調用瞭 inheritableThreadLocal.remove() 方法來清除 InheritableThreadLocal 對象的值,並釋放相關的資源。這是一種良好的習慣,可以避免內存泄漏和數據污染等問題。
3、相關問題
1.請簡述Java中的多線程通信機制,並解釋一下為什麼需要多線程通信?
答:Java中的多線程通信機制是通過使用管道和共享變量來實現的。管道可以用來實現多個線程之間的數據傳遞和同步,共享變量可以用來實現多個線程之間的數據共享和同步。
2.Java 中,在多個線程之間共享數據的方式主要有以下幾種:
1)共享變量:可以將需要共享的變量定義為靜態變量或公共變量,然後通過同步控制機制(例如 synchronized 關鍵字、Lock 接口等)保證多線程訪問這些變量時的安全性。
2)ThreadLocal:通過 ThreadLocal 類可以在每個線程中創建獨立的變量副本,從而避免瞭對共享變量的競爭。
3)Callable 和 Future 接口:在子線程執行任務後,可以通過 Callable 和 Future 接口返回結果給主線程。主線程可以通過 Future.get() 方法獲取子線程的執行結果,從而完成數據共享。
4)BlockingQueue:可以使用 BlockingQueue 來實現數據共享和通信,生產者線程向 BlockingQueue 中添加數據,消費者線程從隊列中獲取數據。
5)CyclicBarrier 和 CountDownLatch:可以使用 CyclicBarrier 和 CountDownLatch 等同步工具來協調多個線程之間的操作,從而實現數據共享。
到此這篇關於深入探究一下Java中不同的線程間數據通信方式的文章就介紹到這瞭,更多相關Java線程數據通信方式內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 新手瞭解java 多線程基礎知識
- Java如何實現多個線程之間共享數據
- Java創建並運行線程的方法
- Java多線程Thread類的使用及註意事項
- 多線程_解決Runnable接口無start()方法的情況