簡體   English   中英

Java線程未響應易失性布爾標志

[英]Java thread not responding to volatile boolean flag

我是Java並發的新手,我遇到了一個非常奇怪的問題:我從一個大文件中讀取並使用了多個工作線程來處理輸入(一些復雜的字符串匹配任務)。 我使用了LinkedBlockingQueue將數據傳輸到工作線程,並使用了worker類中的易失性布爾標志來在到達文件結尾時響應信號。

但是,我無法使工作線程正常停止。 最后,該程序的CPU使用率幾乎為零,但該程序不會正常終止。

簡化的代碼如下。 我刪除了真實的代碼,並用一個簡單的單詞計數器替換了它們。 但是效果是一樣的。 在處理了整個文件之后,輔助線程將不會終止,並且在主線程中將boolean標志設置為true。

main

public class MultiThreadTestEntry
{
    private static String inputFileLocation = "someFile";
    private static int numbOfThread = 3;

    public static void main(String[] args)
    {
        int i = 0;
        Worker[] workers = new Worker[numbOfThread];
        Scanner input = GetIO.getTextInput(inputFileLocation);
        String temp = null;
        ExecutorService es = Executors.newFixedThreadPool(numbOfThread);
        LinkedBlockingQueue<String> dataQueue = new LinkedBlockingQueue<String>(1024);

        for(i = 0 ; i < numbOfThread ; i ++)
        {
            workers[i] = new Worker(dataQueue);
            workers[i].setIsDone(false);
            es.execute(workers[i]);
        }

        try
        {
            while(input.hasNext())
            {
                temp = input.nextLine().trim();
                dataQueue.put(temp);
            }
        }
        catch (InterruptedException e)
        {
            Thread.currentThread().interrupt();
        }

        input.close();

        for(i = 0 ; i < numbOfThread ; i ++)
        {
            workers[i].setIsDone(true);
        }

        es.shutdown();

        try 
        {
            es.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (InterruptedException e)
        {
            Thread.currentThread().interrupt();
        }
    }
}

worker

public class Worker implements Runnable
{
    private LinkedBlockingQueue<String> dataQueue = null;
    private volatile boolean isDone = false;

    public Worker(LinkedBlockingQueue<String> dataQueue)
    {
        this.dataQueue = dataQueue;
    }

    @Override
    public void run()
    {
        String temp = null;
        long count = 0;
        System.out.println(Thread.currentThread().getName() + " running...");

        try
        {
            while(!isDone || !dataQueue.isEmpty())
            {
                temp = dataQueue.take();
                count = temp.length() + count;

                if(count%1000 == 0)
                {
                    System.out.println(Thread.currentThread().getName() + " : " + count);
                }
            }

            System.out.println("Final result: " + Thread.currentThread().getName() + " : " + count);
        }
        catch (InterruptedException e)
        {

        }
    }

    public void setIsDone(boolean isDone)
    {
        this.isDone = isDone;
    }
}

有什么建議為什么會發生這種情況?

非常感謝你。

正如Dan Getz所說的那樣,您的worker take()會等到某個元素變為可用,但Queue可能為空。

在您的代碼中,您檢查隊列是否為空,但是在檢查之后,沒有什么阻止其他Worker讀取並從該元素中刪除該元素。

如果隊列僅包含一個元素,並且t1t2是兩個線程,則可能會發生以下情況:

t2.isEmpty(); // -> false
t1.isEmpty(); // -> false
t2.take(); // now the queue is empty 
t1.take(); // wait forever

在這種情況下, t1將“永遠”等待。

您可以通過使用poll而不是take並檢查結果是否為null來避免這種情況

public void run()
{
    String temp = null;
    long count = 0;
    System.out.println(Thread.currentThread().getName() + " running...");

    try
    {
        while(!isDone || !dataQueue.isEmpty())
        {
            temp = dataQueue.poll(2, TimeUnit.SECONDS);
            if (temp == null) 
                // re-check if this was really the last element
                continue;

            count = temp.length() + count;

            if(count%1000 == 0)
            {
                System.out.println(Thread.currentThread().getName() + " : " + count);
            }
        }

        System.out.println("Final result: " + Thread.currentThread().getName() + " : " + count);
    }
    catch (InterruptedException e)
    {
        // here it is important to restore the interrupted flag!
        Thread.currentThread().interrupt();
    }
}

暫無
暫無

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

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