多线程写多个文件

metallica-run 2015-01-27 05:23:04
我想实现一个多线程写入多个文件的程序.每个线程创建一个写入对象进行写入.比如创建从1到100为文件名的文件,每个文件写入一个数字,但是在写入中会有文件丢失的现象,最后不够100个文件.不太明白为什么会出现这个情况.同样的代码用来读多个文件将结果存入list中就没有问题.具体代码如下.忘各位大牛指教.

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.concurrent.*;

public class MutiWriter {
public static final int threadSize = 4;
public volatile boolean running = false;
public Thread[] pool;
public BlockingQueue<Integer> producer = new LinkedBlockingQueue<Integer>();
public String path ;
public int index = 1;

public MutiWriter(){
this(threadSize);
}

public MutiWriter(int size){
pool = new Thread[size];
Writer writer = new Writer();
for(int i = 0; i <size; i++){
pool[i] = new Thread(writer,"thread"+i);
pool[i].start();
}
running = true;
}

private class Writer implements Runnable{
public void run(){
int temp = 0;
try {
while((temp=producer.take()) != 0){
doWork(temp);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
producer.put(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public void doWork(int num){
// System.out.println("ThreadNow " + Thread.currentThread().getName());
try {
BufferedWriter out = new BufferedWriter(new FileWriter(path+index+".txt"));
out.write(String.valueOf(num));
out.flush();
out.close();
System.out.println(index);
} catch (IOException e) {
e.printStackTrace();
}
index++;
}
}

public void addProducer(int num){
for(int i = 1; i < num; i++){
try {
producer.put(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public void shutdown(){
if(running){
running = false;
}
try {
producer.put(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public void waitting(){
if(running || !producer.contains(0)){
throw new IllegalStateException("shutdown first");
}
try {
producer.put(0);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
for(Thread t : pool){
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public static void main(String[] args){
MutiWriter instance = new MutiWriter(threadSize);
instance.addProducer(101);
instance.shutdown();
instance.waitting();
}
}
...全文
278 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
O_森_O 2015-01-28
  • 打赏
  • 举报
回复
这是一个典型的多线程同步问题,因为对index共享资源做++操作没有同步导致的,改进代码如下:
package testproject;


import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.concurrent.*;

public class MutiWriter {

    public static final int threadSize = 4;
    public volatile boolean running = false;
    public Thread[] pool;
    public BlockingQueue<Integer> producer = new LinkedBlockingQueue<Integer>();
    public String path;
    public int index = 1;

    public MutiWriter() {
        this(threadSize);
    }

    public MutiWriter(int size) {
        pool = new Thread[size];
        Writer writer = new Writer();
        for (int i = 0; i < size; i++) {
            pool[i] = new Thread(writer, "thread" + i);
            pool[i].start();
        }
        running = true;
    }

    private class Writer implements Runnable {

        public void run() {
            int temp = 0;
            try {
                while ((temp = producer.take()) != 0) {
                    doWork(temp);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                producer.put(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        public void doWork(int num) {
//			System.out.println("ThreadNow " + Thread.currentThread().getName());
            try {
                BufferedWriter out = new BufferedWriter(new FileWriter(path + getIndex() + ".txt"));
                out.write(String.valueOf(num));
                out.flush();
                out.close();
                System.out.println(index);
            } catch (IOException e) {
                e.printStackTrace();
            }
            index++;
        }
    }
    
    // 这里需要同步
    synchronized int getIndex(){
        int idx=this.index;
        this.index++;
        return idx;
    }

    public void addProducer(int num) {
        for (int i = 1; i < num; i++) {
            try {
                producer.put(i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void shutdown() {
        if (running) {
            running = false;
        }
        try {
            producer.put(0);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void waitting() {
        if (running || !producer.contains(0)) {
            throw new IllegalStateException("shutdown first");
        }
        try {
            producer.put(0);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        for (Thread t : pool) {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        MutiWriter instance = new MutiWriter(threadSize);
        instance.addProducer(101);
        instance.shutdown();
        instance.waitting();
    }
}
dgqjava 2015-01-28
  • 打赏
  • 举报
回复
改成这样就没问题了
public class T {

	public static final int THREAD_SIZE = 4;
	public Thread[] pool;
	public BlockingQueue<Integer> producer = new LinkedBlockingQueue<Integer>();
	public String path = "D:/";
	public int index = 1;

	public T() {
		this(THREAD_SIZE);
	}

	public T(int size) {
		pool = new Thread[size];
		Writer writer = new Writer();
		for (int i = 0; i < size; i++) {
			pool[i] = new Thread(writer, "thread" + i);
			pool[i].start();
		}
	}

	private class Writer implements Runnable {

		public void run() {
			int temp = 0;
			try {
				while ((temp = producer.take()) != 0) {
					doWork(temp);
				}
				producer.put(0);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		public void doWork(int num) {
			BufferedWriter out = null;
			try {
				out = new BufferedWriter(new FileWriter(path + num + ".txt"));
				out.write(String.valueOf(num));
				out.flush();
				System.out.println(num);
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if(null != out) {
					try {
						out.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	public void addProducer(int num) throws Exception {
		for (int i = 1; i <= num; i++) {
			producer.put(i);
		}
		producer.put(0);
	}

	public static void main(String[] args) throws Exception {
		T instance = new T(THREAD_SIZE);
		instance.addProducer(100);
	}
}
shixitong 2015-01-28
  • 打赏
  • 举报
回复
主要问题出现在public int index = 1;变量对多个线程共享 有可能出现线程1访问的时候这个变量值是1,线程2访问的时候还是1,因为你线程执行并不是同步的 1、可以象一楼说的那样给index加个同步,但是要把doWork中的index++去掉 2、还可以给这个doWork加个synchronized修饰符(这个保证是有序的)
skyhitnow 2015-01-28
  • 打赏
  • 举报
回复
io操作不是不可中断吗?应该多出来,怎么会少?
淡定的峰哥 2015-01-28
  • 打赏
  • 举报
回复
把index变量换成AtomicInteger类型的即可 然后取数据是index.get() +1换成index.incrementAndGet()
dgqjava 2015-01-28
  • 打赏
  • 举报
回复
没那么简单, 问题很多, 楼上的做法还是有问题

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧