Java固定线程池争用条件?

Java固定线程池争用条件?,java,multithreading,thread-safety,race-condition,synchronized,Java,Multithreading,Thread Safety,Race Condition,Synchronized,考虑以下代码: private static final Object LOCK = new Object(); private static final ExecutorService executorService = Executors.newFixedThreadPool(10); // Also used for a few other tasks. public static void save(Object o) { String s = serialize(o);

考虑以下代码:

private static final Object LOCK = new Object();
private static final ExecutorService executorService = Executors.newFixedThreadPool(10); // Also used for a few other tasks.

public static void save(Object o) {
    String s = serialize(o);
    executorService.submit(() -> {
        // Do we have a race condition here?
        synchronized (LOCK) {
            saveToFile(s, new File("test.txt")); // overwrites the file
        }
    });
}

public static void main(String[] args) {
    save(args[0]);
    save(args[1]);
}

save(对象o)
仅在主线程上调用。我知道线程池会按顺序处理内部队列中提交的任务,但理论上会发生这种情况吗?在达到
synchronized(LOCK)
之前会有竞争条件,并且文件输出是
args[0]

如果是,如何避免这种情况?我知道单线程执行器肯定能解决这个问题,但如果可能的话,我想使用这个线程池

编辑:我认为一种可能的方法是使用
队列

private static final Queue<String> queue = new ConcurrentLinkedQueue<>();

public static void save(Object o) {
    queue.add(serialize(o));
    executorService.submit(() -> {
        synchronized (LOCK) {
            saveToFile(queue.remove(), new File("test.txt"));
        }
    });
}
私有静态最终队列队列=新的ConcurrentLinkedQueue();
公共静态无效保存(对象o){
添加(序列化(o));
executorService.submit(()->{
已同步(锁定){
saveToFile(queue.remove(),新文件(“test.txt”);
}
});
}

在像您这样的生产者/消费者模式中,您通常通过在(多个)生产者和(单个)消费者之间传输任务。只有一个使用者这一事实确保了执行的顺序

所以在伪代码中,它应该是这样的:

val queue = ArrayBlockingQueue() //could be another BlockingQueue
val executor = ...

main {
  executor.submit(consumer)
  queue.put(args[0])
  queue.put(args[1])
}

consumer() {
  try {
    while (true) {
      val file = queue.take() //blocks until a file is added to the queue
      save(file)
    }
  } catch (InterruptedException e) {
    Thread.currentThread(interrupt()) //restore the interrupt flag
    //do nothing, just exit
  }
}

如果添加更多使用者,则无法保证文件将按顺序处理。但是,您可以添加任意数量的生产者(即从不同线程添加到队列)。

“在达到
同步(锁定)
之前存在竞争条件”-->是。“文件输出为
args[0]
”-->并不总是这样,这取决于比赛的结果。“但是,你想避免什么呢?”布巴兰说。输出应该是
args[1]
保证的。如果
args[1]
是您想要的输出,为什么要调用
args[0]
?或者您需要输出
args[1]
,仅仅因为它是最后一个提交的?我想我找到了一种方法,但是我想知道是否有更好的解决方案。您可以创建一个锁、一个条件和一个公共计数器,每次,程序等待最后一个完成。我建议将方法的名称更改为consumer(),因为该方法正在使用而不是生成。很有趣,但这样做会在整个时间内“占用”池中的一个线程。不完全是我要找的。但是我喜欢这个主意。谢谢。你说“占据一条线”是什么意思?线程要么正在做一些工作,保存文件,要么将处于等待状态(不使用任何CPU资源)。我知道它在等待时不使用CPU。但是池中有固定数量的线程。那么,其中一个就不能再用于其他任务了。为什么不让使用者获取一个元素,而不是循环,并在元素放入队列的次数内提交使用者?这避免了阻塞线程,并且仍然保证按队列顺序写入。