簡體   English   中英

兩個線程之間的靜態值共享Java

[英]static Value Sharing between two Threads Java

我有兩個不同的子進程在兩個不同的線程中運行兩個不同的命令。第二個線程更新靜態變量中的值,第一個線程獲取並使用該值。

流程應該是這樣的:Thread2更新靜態變量,並且thread1從靜態變量中獲取值,然后將其打印..但是發生的流程是thread1首先從靜態變量中獲取了值。 在這種情況下,它具有空值,然后thread2更新該值。

兩個線程並行運行,我正在使用ExecutorService類來執行此操作。 我正在使用Runtime類運行命令,並使用while循環在兩個線程上連續讀取Stream的輸出。

Thread1繼續提供(X,Y)值,線程2僅在獲取文本時才給出值。

我得到的輸出:

(12,123)null-> thread2沒有獲得任何值,因此它不會更新,thread1將從靜態變量獲得null
(123,334)null->線程1從靜態變量中獲取值並使用它,線程2然后將值“ Hello”更新為靜態變量
(134,654)“ Hello”-> thread1拾取並使用“ Hello”,然后thread2將值“ World”更新為靜態變量

預期產量:

(12,123)null-> thread2沒有獲得任何值,因此它不會更新,thread1將從靜態變量獲得null
(123,334)“ Hello”-> thread2將值“ Hello”更新為靜態變量,thread1拾取並使用它
(134,654)“世界”->線程2將值“世界”更新為靜態變量,線程1拾取並使用它

我也使用了volatile變量,但是輸出沒有改變。 我在這里想念什么嗎? 請幫忙...

您可以使用java.util.concurrent.Semaphore(從Java 5開始)來控制同時訪問它們共有的變量的線程數。您可以使用允許執行以下操作的線程數來實例化此類。使用它們的共同點,如果您傳遞0,則意味着他們都不能修改它。

public class Threaad extends Thread{
volatile static String string;
public static void main(String[] args) {
    Semaphore semaphore = new Semaphore(0);
    Thread writer = new Write(semaphore);
    writer.setName("writer");
    Thread reader = new Read(semaphore);
    reader.setName("reader");
    ExecutorService service = Executors.newCachedThreadPool();
    service.execute(writer);
    service.execute(reader);
    service.shutdown();
}
}
class Write extends Thread{
    private Semaphore semaphore;
    Write(Semaphore semaphore){
        this.semaphore = semaphore;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            Threaad.string = String.valueOf(i);
            semaphore.release();
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class Read extends Thread{
    private Semaphore semaphore;
    Read(Semaphore semaphore){
        this.semaphore = semaphore;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                semaphore.acquire();
                System.out.println(Threaad.string);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

使用線程時不要做的事情:在沒有正確同步的情況下寫入和讀取相同的變量。 您違反了此規則,因此遇到了不確定結果的預期問題。

想象以下執行流程:

T1: set var to "Hello"
T2: checks var and notices it is a String, proceeds to print it.
T1: set var to null
T2: prints var. (which is already null again)

可能的解決方案是T2首先將值復制到線程局部變量,然后繼續對該變量進行操作,即:

while (running) {
  final String localString = staticString;
  if (localString != null) {
    System.out.println(localString);
  }
}

這樣,您就可以創建變量當前值的“快照”,並且實際上將輸出當時已快照的內容。 但是,這仍然不是在線程之間進行同步的有效方法,因為快照狀態是完全隨機的。 想象發生以下情況:

T1: set var to "hello"
T1: set var to null
T2: checks var, it is null, do nothing.
T1: set var to "world"
T1: set var to null
T2: checks var, it is null, do nothing.

使用線程時,請記住,除非強制執行,否則任何時候任何線程的狀態始終是不確定的。

有幾種簡單的方法可以強制實現特定狀態的synchronized ,這基本上意味着“將整個事情擱置,以便我可以做我的工作”,但是這效率很低,因為如果不斷地將所有內容放在上面,則沒有並行工作的意義。保持。

從架構的角度來看,使用觸發器是一種更好的處理線程的方法。 在您的情況下,編寫器線程可能具有僅包含相關信息(要輸出的字符串)的隊列 ,而生產者線程會將字符串放入該隊列:

T2: checks queue, it is empty, do nothing.
T1: t1.put("Hello")
T2: checks queue, it contains "Hello", print that.
T2: checks queue, it is empty, do nothing.
T2: checks queue, it is empty, do nothing.
T1: t1.put("World")
T2: checks queue, it contains "World", print that.

我建議通讀並發包以了解Java提供的工具。 使用這些幾乎可以解決所有問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM