如何在java中的文件中只写一次标题行

时间:2015-09-17 09:37:39

标签: java multithreading

我在java中使用executor服务创建了多个线程。 在执行这些线程期间的任何错误,我想写一些东西到文件。所以基本上我维护一个文件来维护踏板的错误信息。

我想将标题行仅作为第一行放在此文件中一次。

以下是我的代码目前的样子:

catch(exception e){
    String csv = "/tmp/data1.csv";
    FileWriter writer;
    try {
        File csvFile = new File(csv);
        writer = new FileWriter(csvFile,true);

        if(!flag) {
            flag = true;
            for(int i=0; i<metaInfo.length; i++){
                writer.append(metaInfo[i]);
                if(i != metaInfo.length-1)
                    writer.append(',');
            }
            writer.append('\n');
        }
        for (String aLine : line) {
            writer.append(aLine);
            writer.append(',');
        }
        writer.append(e.getMessage());
        writer.append('\n');
        writer.flush();
        writer.close();
    } catch (IOException e1) {
        e1.printStackTrace();
    }
}

我维护一个标志只写一次标题行。 现在我只能将标题行放入一个文件中。 但是当我并行运行多个线程时,我有时会看到标题不是放在第一行而是放在不同的位置。

解决这个问题的方法是什么?

3 个答案:

答案 0 :(得分:3)

一个应用程序,其中每个打开相同文件并写入它的多个线程不起作用。您将以不可预测的方式从不同的线程交错出现问题。

如果你想做这种事,那么:

  • 线程需要共享一个FileWriter对象
  • 他们需要在访问对象时进行同步,
  • 他们(可能)需要使用互斥锁,以便每个线程到达write一个完整的行(或其他)。

我还建议将FileWriter包裹在BufferedWriter

那么这与你的问题有何关系?

简单。如果您按照我的描述实现输出代码,那么创建共享FileWriter的线程可以在将对象发布到其他线程之前编写标题行。

答案 1 :(得分:2)

在这种情况下,您可以使用共享AtomicBoolean

AtomicBoolean headerWritten = new AtomicBoolean();

// in parallelized code:

if(headerWritten.compareAndSet(false, true)) {
    ... // write header here
}

compareAndSet(false, true)检查当前值,如果false,则将其更改为true并返回true,否则返回false。整个操作以原子方式执行,但没有锁定。因此,它保证最多只能写一次标题。

另请注意,在我回答您的问题时,您的代码中存在更多问题,这些问题在@StephenC答案中表示。

答案 2 :(得分:1)

你的情况是这样的

class Main {
    public static void main(String ag[]) {
        new Thread(new MyRun()).start();
        new Thread(new MyRun()).start();
        new Thread(new MyRun()).start();
        new Thread(new MyRun()).start();
    }
}

class MyRun implements Runnable {
    static boolean flag = false;

    public void run() {
        if (!flag) {
            flag = true;

            //simulate doing some stuff
            try {Thread.sleep((long) (Math.random()*1000));
            } catch (InterruptedException e) {}

            System.out.println("header");
        }
        System.out.println("other stuff");
    }

}

问题是if(!flag){...}块可以同时执行,并且当第一个线程仍在工作时,第二个线程可以更快地运行并在第一个线程之前写入行。

一种可能的解决方案是同步这些指令

class MyRun implements Runnable {
    static boolean flag = false;
    static Object lock=new Object();

    public void run() {
        synchronized (lock) {
            if (!flag) {
                flag = true;

                //simulate doing some stuff
                try {Thread.sleep((long) (Math.random()*1000));
                } catch (InterruptedException e) {}

                System.out.println("header");
            }
        }
        System.out.println("other stuff");
    }

}

或使用Lock个对象,或将everythin放入方法并同步方法。还有其他1000种方法,我只想给你一个想法。