我在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();
}
}
我维护一个标志只写一次标题行。 现在我只能将标题行放入一个文件中。 但是当我并行运行多个线程时,我有时会看到标题不是放在第一行而是放在不同的位置。
解决这个问题的方法是什么?
答案 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种方法,我只想给你一个想法。