写入同一文件时偶尔会阻塞线程

时间:2017-04-28 14:16:47

标签: java multithreading

我试图使用两个单独的线程读取两个文本文件(具有相同的行数,即10000),一个文件包含字符串,另一个文件包含整数。之后我想在结果集中的相应位置写入另一个文本文件(String,Integer)值,每个值都在不同的行上。出于这些目的,我使用了两个实现Runnable接口的类。

我面临的问题是,每次运行程序时,其中一个线程都有可能阻止执行,我不明白为什么考虑我正在使用wait()和notify( )在synchronized块中。更具体地说,有时程序运行成功完成执行,而在大多数情况下它会在各个阶段停止(例如,写入10000行,甚至约500行)。

citireInteger是对正在读取整数文件的其他线程的引用。

以下是分别处理从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();
    }
}

读取整数文件的线程:

    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();
    }
}

2 个答案:

答案 0 :(得分:0)

发生的事情是,一个线程在另一个线程上调用notifyAll,然后在同步其自己的编写器之前切换到调用wait。另一个线程执行写操作,在其编写器上进行同步,并调用wait。然后第一个线程再次切换,在其编写器上同步,并调用wait。这是你的僵局。

最好让两个线程在同一个对象上同步写入。最好的方法是以线程安全的方式将数据存储在内存中,一旦从两个线程读取完毕,就从单个线程写入。

答案 1 :(得分:0)

当您通知另一个线程时,另一个线程只会看到其他线程正在等待它。我的另一个线程在同步块之外,并且在通知之后进入同步块,然后它将等待一个不会发生的通知,或者更确切地说,比在它开始之前发生的通知等待它。 很难真正确定这项练习的目的是什么,但我猜测这是关于两个线程轮流做写。好的,那么,如何使synchronized(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();
       }
    }