簡體   English   中英

寫入同一文件時,線程偶爾會阻塞

[英]Threads occasionally blocking while writing to the same file

我試圖使用兩個單獨的線程從兩個文本文件(具有相同的行數,即10000)中讀取文件,一個文件包含字符串,另一個文件包含整數。 之后,我想從結果集中的相應位置寫入另一個文本文件(String,Integer)值,每個位置在不同的行上。 為此,我使用兩個實現Runnable接口的類。

我面臨的問題是,每次運行程序時,線程之一都有可能阻塞執行,並且我不明白為什么要考慮在一個線程中使用wait()和notify() synchronized塊。 更具體地說,有時程序會成功運行以完成執行過程,而在大多數情況下,它會在各個階段停止(例如,在寫入的10000行中大約有3000條記錄,甚至有500條記錄)。

citireInteger是對另一個讀取Integer文件的線程的引用。

這是分別處理從String和Integer文件讀取的類中的相關代碼:

@Override
public void run(){

    ........
    try {
        pw = new PrintWriter(new BufferedWriter(new FileWriter("rezultat.txt", true)));

        for(int i = 0; i < strings.size(); i++){

            synchronized(this){
                pw.write(strings.get(i));
            }

            synchronized(citireInteger){
                citireInteger.notifyAll();
            }

            try{
                synchronized(this){
                    wait();
                }
            } catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    } catch(FileNotFoundException e){
        e.printStackTrace();
    } catch(IOException e){
        e.printStackTrace();
    } finally{
        pw.close();
    }

    synchronized(citireInteger){
        citireInteger.notify();
    }
}

讀取Integer文件的線程:

    public void run(){

    ...........

    try{
        pw = new PrintWriter(new BufferedWriter(new FileWriter("rezultat.txt", true)));

        for(int i = 0; i < ints.size(); i++){

            synchronized(this){
                pw.write(ints.get(i) + '\n');
                System.out.println(ints.get(i));
            }
            synchronized(citireString){
                citireString.notifyAll();
            }

            try{
                synchronized(this){
                    wait();
                }
            } catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    } catch(FileNotFoundException e){
        e.printStackTrace();
    } catch(IOException e){
        e.printStackTrace();
    } finally{
        pw.close();
    }

    synchronized(citireString){
        citireString.notify();
    }
}

發生的情況是,一個線程正在另一線程上調用notifyAll ,然后在與自己的編寫器同步以調用wait之前被切換出去。 另一個線程進行寫操作,在其寫程序上進行同步,然后調用wait 然后,第一個線程再次進入,在其編寫器上同步,並調用wait 有你的僵局。

最好讓兩個線程在同一個對象上進行同步寫入。 最好將數據以線程安全的方式存儲在內存中,並在從兩個線程讀取完成后從單個線程寫入數據。

當您通知另一個線程時,另一個線程將僅在其他線程正在等待時看到它。 如果另一個線程在該同步塊之外,則在收到通知進入該同步塊,然后它將等待一個通知,該通知不會發生,或者寧可發生,也不會在它開始等待之前發生。 很難真正確定此練習的目標是什么,但是我猜想這是兩個線程輪流執行寫操作的原因。 好的,那么,如何使synced(citireInt / String)塊包含整個代碼! 這樣,試圖獲得鎖的另一個線程將僅在另一個線程正在等待時才獲得該鎖。 我認為這不會保證任何阻塞,結果是兩個線程都一一輪換。

編輯:完全不像我描述的那樣,但是要點是同步的地方...

   public void run()
   {
       ...........

       try
       {
           pw = new PrintWriter(new BufferedWriter(new FileWriter("rezultat.txt", true)));

           synchronized(this)
           {
               for(int i = 0; i < ints.size(); i++)
               {
                   pw.write(ints.get(i) + '\n');
                   System.out.println(ints.get(i));

                   synchronized (citireString)
                   {
                       citireString.notifyAll();
                   }

                   try
                   {
                       wait();
                   }
                   catch (InterruptedException e)
                   {
                       e.printStackTrace();
                   }
               }
           }
       }
       catch (Throwable e)
       {
           e.printStackTrace();
       }
       finally
       {
           pw.close();
       }
    }

暫無
暫無

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

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