簡體   English   中英

對多個線程正確的方法到System.setErr()?

[英]Correct way to System.setErr() for multiple threads?

因此,我有一個使用固定線程池的Java應用程序來執行一些代碼。 該代碼包括使用輸出到System.err的第三方庫。 當我讓這段代碼執行單線程時,我將System.err重定向到PrintStream,最終將其輸出到log4j日志。 基本上看起來像這樣:

 PrintStream oldErr = System.err;
 System.setErr(new PrintStream(/* custom logging stream here */));

 try
 {
     // do computationally expensive task here
 }
 finally
 {
     System.setErr(oldErr);
 }

如預期般運作。 輸出打印到日志文件而不是控制台,並且可以通過更改log4j配置完全刪除輸出。 完善。

當我開始添加多線程時,我做了一些研究,並遇到了一個SO問題: 在多線程Java程序中,每個線程是否都有其自己的System.out副本? ,這意味着我應該在啟動線程池之前執行一次System.setErr(),然后一切准備就緒。 只是事實並非如此。 我的代碼現在看起來像這樣:

 PrintStream oldErr = System.err;
 System.setErr(new PrintStream(/* custom logging stream here */));

 ExecutorService threadPool = Executors.newFixedThreadPool(maxThreadCount);

 try
 {
     // shove computationally expensive task off to a thread
     //   using threadPool.execute()
 }
 finally
 {
     System.setErr(oldErr);
 }

但是,在啟動線程池之前調用System.setErr()的影響為零。 所有線程都將其輸出打印到System.err,好像我根本沒有進行調用一樣。 討厭鬼!

我還嘗試在執行任務時讓線程調用System.setErr(),但與此同時存在一些明顯的競爭條件問題:向控制台的間歇性輸出以及普遍的骯臟感。 在一次測試運行中,甚至看起來他們陷入僵局。

我是否缺少簡單的東西? FWIW,這是我的JVM詳細信息:

java version "1.6.0_21"
Java(TM) SE Runtime Environment (build 1.6.0_21-b07)
Java HotSpot(TM) 64-Bit Server VM (build 17.0-b17, mixed mode)

謝謝。

編輯:我的問題基本上可以通過接受的答案解決,但是出於完整性考慮,我想補充一點,我無法使用Futures和get()解決我的特殊情況。 我的單個任務占用大量RAM,但持續時間各不相同,因此我不得不使用一個小的阻塞隊列,如Java答案:ExecutorService所述,該阻塞隊列在一定隊列大小后提交時會阻塞 我基本上陷入了這樣一種陷阱:認為newFixedThreadPool()中的默認值在我的情況下不起作用,而實際上卻不行,而Brian的回答有助於揭露那些錯誤的假設。 謝謝布萊恩!

以下SSCCE完全可以滿足您的期望和期望:

public class App
{
    public static void main(String[] args) throws FileNotFoundException, InterruptedException, ExecutionException 
    {
        PrintStream oldErr = System.err;
        System.setErr(new PrintStream(new File("test")));

        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        List<Future<?>> fList = new LinkedList<Future<?>>();
        for (int i = 0; i < 5; i++)
        {
            fList.add(threadPool.submit(new Runnable() {

                @Override
                public void run()
                {
                    System.err.println("This is to the err stream");
                }

            }));
        }

        for (Future<?> f : fList)
        {
            f.get();
        }

        threadPool.shutdown();

        System.setErr(oldErr);
        System.err.println("This is to the err stream");
    }
}

運行此示例后,文件“ test”包含5行,每行顯示“ This is to err stream”,最后,在控制台上又打印了一行。

您顯示的代碼片段調用System.setErr(oldErr); finally塊中...您是否已在該try塊中等待所有任務完成?

如果不是這樣,它將解釋您在注釋中所做的聲明,即“我將看到輸出的片段打印到System.err,而片段打印到我的日志文件” ……這幾乎是您期望發生的事情。 .submit()是一個非阻塞調用,它返回一個Future 您正在運行任務時重置流。

暫無
暫無

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

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