Java 在不同线程中处理文件写入的正确方法
我正在寻找写入文件多次(100k+)和写入将发生在一个脆弱的网络。为此,我正在考虑使用JavaJava 在不同线程中处理文件写入的正确方法,java,multithreading,thread-safety,threadpool,executorservice,Java,Multithreading,Thread Safety,Threadpool,Executorservice,我正在寻找写入文件多次(100k+)和写入将发生在一个脆弱的网络。为此,我正在考虑使用JavaExecutorService来帮助生成线程,但我不确定哪种设置组合能够正确地实现以下操作: 一次只允许进行一次写入(当然是订购事宜) 允许写操作有足够的时间进行每次写操作(比如说5秒),此时只需 如果写入速度慢,请让执行器在队列中收集写入并等待 在线程队列为空之前,不要允许整个程序退出 用编剧把线分开。也就是说,如果同一个writer出现在这个函数中,那么将它放在它自己的队列中。如果输入了不同的wri
ExecutorService
来帮助生成线程,但我不确定哪种设置组合能够正确地实现以下操作:
.wait()
和.notify()
命令来实现。然而,我只是不确定如何精确地使用executor API来完成这项工作
以下是我得到的:
private void writeToFileInSeperateThread(final PrintWriter writer, final String text) {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
executor.submit(new Thread(new Runnable() {
public void run() {
writer.println(text);
}
})).get(5L, TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
}
executor.shutdown();
}
在单个进程中,该方法将被调用100k多次,因此我不确定每次是创建一个新的ExcutorService
实例,还是使用相同的实例?(在我尝试使用同一个线程时,我不断得到一些异常,我认为这些异常与.newSingleThreadExecutor()
指令有关
希望保持Java 5兼容,但Java 6可以。在Windows XP/7上运行
更新:
这似乎在初始测试中起到了作用:
private class WriterStringPair {
public final PrintWriter writer;
public final String text;
public WriterStringPair(PrintWriter writer, String text) {
this.writer = writer;
this.text = text;
}
}
private void writeTextInSeperateThread(Writer writer, String text) {
try {
textQueue.offer(new WriterStringPair(writer, text), 300L, TimeUnit.SECONDS);
} catch (InterruptedException e) {
errOut.println(e);
e.printStackTrace();
}
}
final BlockingQueue<WriterStringPair> textQueue = new ArrayBlockingQueue<WriterStringPair>(500);
private void setWritingThread() {
new Thread((new Runnable() {
public void run() {
WriterStringPair q;
while (!shutdown && !Thread.currentThread().isInterrupted()) {
try {
q = textQueue.poll(1L, TimeUnit.SECONDS);
if (q != null) {
q.writer.write(q.text + "\n");
q.writer.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
})).start();
}
私有类WriterStringPair{
公共最终印刷作者;
公共最终字符串文本;
公共WriterStringPair(PrintWriter编写器,字符串文本){
this.writer=writer;
this.text=文本;
}
}
私有void WriteTextInsperateThread(编写器编写器,字符串文本){
试一试{
textQueue.offer(新的WriterStringPair(writer,text),300L,时间单位为秒);
}捕捉(中断异常e){
打印错误(e);
e、 printStackTrace();
}
}
最终阻塞队列textQueue=新的ArrayBlockingQueue(500);
私有void setWritingThread(){
新线程((新可运行的(){
公开募捐{
WriterStringPair q;
而(!shutdown&!Thread.currentThread().isInterrupted()){
试一试{
q=textQueue.poll(1L,时间单位:秒);
如果(q!=null){
q、 writer.write(q.text+“\n”);
q、 writer.flush();
}
}捕获(例外e){
e、 printStackTrace();
}
}
}
})).start();
}
如果不了解更多关于您在“脆弱”网络上编写文件的详细信息及其含义,我们很难给出具体信息。但下面是一些需要思考的问题
我会计算出多少并发写入程序在这里为您提供了最好的性能,或者在目标上提供了最可靠的输出。然后,您应该启动固定数量的这些写入程序,每个写入程序都从共享的BlockingQueue
(或者每个写入程序一个队列,如果有必要的话)。您应该很快超过IO或网络带宽,因此从5个左右的写入程序开始,并根据需要进行上下操作
public void run() {
writer.println(text);
}
是的,你不想在每行一个作业的情况下做这种事情。最好将字符串文本
放入阻塞队列
,然后让你的writerRunnable
类在ExecutorService
中运行,并从该队列中退出队列,并且仅在队列为空或sh时停止utdown
boolean已设置
正如Peter提到的,在使用排队的文本字符串填充内存时需要小心。如果输入的文本较大,则应将BlockingQueue
的限制设置为几百左右
我不确定每次是创建一个新的ExecutorService
实例,还是使用同一个实例
当然,您应该有一个单一的服务,而不是一次又一次地创建一个
我相信这可以通过executor特性的组合以及主程序对象上的.wait()和.notify()命令来实现
如果写得正确,您不需要使用“等待并通知”。我会有一个volatile boolean shutdown=false
,您的所有编写者都会看到它。他们每个人都会通过查看关闭来从文本队列中退出。类似于:
while (!shutdown && !Thread.currentThread().isInterrupgted()) {
String text = textQueue.poll(1, TimeUnit.SECONDS);
if (text != null) {
// write the text
}
}
如果写入失败或其他情况,您可以重试或做任何必要的操作。在不了解有关您通过“脆弱”网络写入文件的详细信息以及方法的情况下,我们很难给出具体信息。但这里有一些事情需要考虑 我会计算出多少并发写入程序在这里为您提供了最好的性能,或者在目标上提供了最可靠的输出。然后,您应该启动固定数量的这些写入程序,每个写入程序都从共享的
BlockingQueue
(或者每个写入程序一个队列,如果有必要的话)。您应该很快超过IO或网络带宽,因此从5个左右的写入程序开始,并根据需要进行上下操作
public void run() {
writer.println(text);
}
是的,你不想在每行一个作业的情况下做这种事情。最好将字符串文本
放入阻塞队列
,然后让你的writerRunnable
类在ExecutorService
中运行,并从该队列中退出队列,并且仅在队列为空或sh时停止utdown
boolean已设置
正如Peter提到的,在使用排队的文本字符串填充内存时需要小心。如果输入的文本较大,则应将BlockingQueue
的限制设置为几百左右
我不确定我是否应该成为crea