问题描述
我想实现一个多线程写入多个文件的程序.每个线程创建一个写入对象进行写入.比如创建从1到100为文件名的文件,每个文件写入一个数字,但是在写入中会有文件丢失的现象,最后不够100个文件.不太明白为什么会出现这个情况.同样的代码用来读多个文件将结果存入list中就没有问题.具体代码如下.忘各位大牛指教.importjava.io.BufferedWriter;importjava.io.File;importjava.io.FileWriter;importjava.io.IOException;importjava.util.concurrent.*;publicclassMutiWriter{publicstaticfinalintthreadSize=4;publicvolatilebooleanrunning=false;publicThread[]pool;publicBlockingQueue<Integer>producer=newLinkedBlockingQueue<Integer>();publicStringpath;publicintindex=1;publicMutiWriter(){this(threadSize);}publicMutiWriter(intsize){pool=newThread[size];Writerwriter=newWriter();for(inti=0;i<size;i++){pool[i]=newThread(writer,"thread"+i);pool[i].start();}running=true;}privateclassWriterimplementsRunnable{publicvoidrun(){inttemp=0;try{while((temp=producer.take())!=0){doWork(temp);}}catch(InterruptedExceptione){e.printStackTrace();}try{producer.put(0);}catch(InterruptedExceptione){e.printStackTrace();}}publicvoiddoWork(intnum){//System.out.println("ThreadNow"+Thread.currentThread().getName());try{BufferedWriterout=newBufferedWriter(newFileWriter(path+index+".txt"));out.write(String.valueOf(num));out.flush();out.close();System.out.println(index);}catch(IOExceptione){e.printStackTrace();}index++;}}publicvoidaddProducer(intnum){for(inti=1;i<num;i++){try{producer.put(i);}catch(InterruptedExceptione){e.printStackTrace();}}}publicvoidshutdown(){if(running){running=false;}try{producer.put(0);}catch(InterruptedExceptione){e.printStackTrace();}}publicvoidwaitting(){if(running||!producer.contains(0)){thrownewIllegalStateException("shutdownfirst");}try{producer.put(0);}catch(InterruptedExceptione1){e1.printStackTrace();}for(Threadt:pool){try{t.join();}catch(InterruptedExceptione){e.printStackTrace();}}}publicstaticvoidmain(String[]args){MutiWriterinstance=newMutiWriter(threadSize);instance.addProducer(101);instance.shutdown();instance.waitting();}}
解决方案
解决方案二:
这是一个典型的多线程同步问题,因为对index共享资源做++操作没有同步导致的,改进代码如下:packagetestproject;importjava.io.BufferedWriter;importjava.io.File;importjava.io.FileWriter;importjava.io.IOException;importjava.util.concurrent.*;publicclassMutiWriter{publicstaticfinalintthreadSize=4;publicvolatilebooleanrunning=false;publicThread[]pool;publicBlockingQueue<Integer>producer=newLinkedBlockingQueue<Integer>();publicStringpath;publicintindex=1;publicMutiWriter(){this(threadSize);}publicMutiWriter(intsize){pool=newThread[size];Writerwriter=newWriter();for(inti=0;i<size;i++){pool[i]=newThread(writer,"thread"+i);pool[i].start();}running=true;}privateclassWriterimplementsRunnable{publicvoidrun(){inttemp=0;try{while((temp=producer.take())!=0){doWork(temp);}}catch(InterruptedExceptione){e.printStackTrace();}try{producer.put(0);}catch(InterruptedExceptione){e.printStackTrace();}}publicvoiddoWork(intnum){//System.out.println("ThreadNow"+Thread.currentThread().getName());try{BufferedWriterout=newBufferedWriter(newFileWriter(path+getIndex()+".txt"));out.write(String.valueOf(num));out.flush();out.close();System.out.println(index);}catch(IOExceptione){e.printStackTrace();}index++;}}//这里需要同步synchronizedintgetIndex(){intidx=this.index;this.index++;returnidx;}publicvoidaddProducer(intnum){for(inti=1;i<num;i++){try{producer.put(i);}catch(InterruptedExceptione){e.printStackTrace();}}}publicvoidshutdown(){if(running){running=false;}try{producer.put(0);}catch(InterruptedExceptione){e.printStackTrace();}}publicvoidwaitting(){if(running||!producer.contains(0)){thrownewIllegalStateException("shutdownfirst");}try{producer.put(0);}catch(InterruptedExceptione1){e1.printStackTrace();}for(Threadt:pool){try{t.join();}catch(InterruptedExceptione){e.printStackTrace();}}}publicstaticvoidmain(String[]args){MutiWriterinstance=newMutiWriter(threadSize);instance.addProducer(101);instance.shutdown();instance.waitting();}}
解决方案三:
没那么简单,问题很多,楼上的做法还是有问题
解决方案四:
把index变量换成AtomicInteger类型的即可然后取数据是index.get()+1换成index.incrementAndGet()
解决方案五:
io操作不是不可中断吗?应该多出来,怎么会少?
解决方案六:
主要问题出现在publicintindex=1;变量对多个线程共享有可能出现线程1访问的时候这个变量值是1,线程2访问的时候还是1,因为你线程执行并不是同步的1、可以象一楼说的那样给index加个同步,但是要把doWork中的index++去掉2、还可以给这个doWork加个synchronized修饰符(这个保证是有序的)
解决方案七:
改成这样就没问题了publicclassT{publicstaticfinalintTHREAD_SIZE=4;publicThread[]pool;publicBlockingQueue<Integer>producer=newLinkedBlockingQueue<Integer>();publicStringpath="D:/";publicintindex=1;publicT(){this(THREAD_SIZE);}publicT(intsize){pool=newThread[size];Writerwriter=newWriter();for(inti=0;i<size;i++){pool[i]=newThread(writer,"thread"+i);pool[i].start();}}privateclassWriterimplementsRunnable{publicvoidrun(){inttemp=0;try{while((temp=producer.take())!=0){doWork(temp);}producer.put(0);}catch(Exceptione){e.printStackTrace();}}publicvoiddoWork(intnum){BufferedWriterout=null;try{out=newBufferedWriter(newFileWriter(path+num+".txt"));out.write(String.valueOf(num));out.flush();System.out.println(num);}catch(IOExceptione){e.printStackTrace();}finally{if(null!=out){try{out.close();}catch(IOExceptione){e.printStackTrace();}}}}}publicvoidaddProducer(intnum)throwsException{for(inti=1;i<=num;i++){producer.put(i);}producer.put(0);}publicstaticvoidmain(String[]args)throwsException{Tinstance=newT(THREAD_SIZE);instance.addProducer(100);}}