首页 > 试题广场 >

一个文件中有10000个数,用Java实现一个多线程程序将这

[问答题]
一个文件中有10000个数,用Java实现一个多线程程序将这个10000个数输出到5个不用文件中(不要求输出到每个文件中的数量相同)。要求启动10个线程,两两一组,分为5组。每组两个线程分别将文件中的奇数和偶数输出到该组对应的一个文件中,需要偶数线程每打印10个偶数以后,就将奇数线程打印10个奇数,如此交替进行。同时需要记录输出进度,每完成1000个数就在控制台中打印当前完成数量,并在所有线程结束后,在控制台打印”Done”.
推荐



运行结果:



编辑于 2015-07-16 17:20:57 回复(11)
自己重写了一下推荐答案,加了些注释方便理解
package threadpackage;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.Random;

/*
 一个文件中有10000个数,用Java实现一个多线程程序将这个10000个数输出到5个不用文件中(不要求输出到每个文件中的数量相同)。
 要求启动10个线程,两两一组,分为5组。
 每组两个线程分别将文件中的奇数和偶数输出到该组对应的一个文件中,
 需要偶数线程每打印10个偶数以后,就将奇数线程打印10个奇数,如此交替进行。
 同时需要记录输出进度,每完成1000个数就在控制台中打印当前完成数量,并在所有线程结束后,在控制台打印”Done”.
 */
/**
 * 分析:可以将10000个数分成5份,每一份(2000个数)对应一组,即两个线程,来分别输出这一份的奇数和偶数,
 * 同时声明一个共享变量,用于统计当前所有线程输出的个数,反映记录的输出进度
 */
public class PrintByThread {
	
	public static void main(String[] args) {
		try {
			//创建一个包含10000数字的输入文件
			PrintWriter pw=new PrintWriter(new FileWriter(new File("input.txt")),true);
			Random random=new Random();
			for (int i = 0; i < 10000; i++) {
				pw.print(Math.abs(random.nextInt())%100+",");
			}
			pw.flush();
			pw.close();
			//读取文件中的数字,分5次读取,每次读取2000个
			BufferedReader reader=new BufferedReader(new FileReader("input.txt"));
			String str=reader.readLine();
			reader.close();
			String[] strs=str.split(",");//将一行字符串全部解析为10000个数字
			int j=0;//10000个数的索引计数
			for (int i = 0; i < 5; i++) {
				int records[]=new int[2000];
				for (int k = 0; k < 2000; k++) {
					records[k]=Integer.parseInt(strs[j]);
					j++;
				}
				//定义输出文件
				PrintWriter writer =new PrintWriter(new FileWriter(new File("output"+i+".txt")),true);
				//定义实现的方法
				ThreadGroup group=new ThreadGroup(records, writer);
				//开启一对儿线程
				new Thread(group).start();
				new Thread(group).start();				
			}			
			
		} catch (Exception e) {
			// TODO: handle exception
		}		
	}	
} 
package threadpackage;

import java.io.PrintWriter;


class ThreadGroup implements Runnable{
	//所有类对象共享的同一个计数器count,记录总共输出的记录总数
	private static int count=0;
	//所有的ThreadGroup类对象共享一个锁,用于count变量的同步,任何一个线程需要修改count变量,必须取得该锁
	private static Object lock=new Object();
	public static final int EVEN=0;//代表偶数
	public static final int ODD=1;//代表奇数
	
	//*********以上静态变量,属于整个类所有***********
	private int type;
	private int records[];
	private PrintWriter writer;//每组共享一个writer,输出到同一个文件
	private int oddPoint=0;//记录每次打印奇数的起始位置
	private int evenPoint=0;//记录每次打印偶数的起始位置
	
	public ThreadGroup(int[] records,PrintWriter writer){
		this.records=records;
		this.writer=writer;
		this.type=EVEN;
	}
	
	//线程方法实现
	public void run() {
		while(print());
		
	}
	
	private synchronized boolean print(){
		for(int i=0;i<10;){
			//如果奇数和偶数都打印完成以后,就直接停止打印循环,等待该线程自己结束
			if (oddPoint>=records.length&&evenPoint>=records.length) {
				notifyAll();
				return false;
			}
			//如果该线程该打印奇数,但奇数已经打印晚了,就直接停止本次10个数的打印,
			//同理偶数,等下次切换打印类型后,再开始打印另外一种类型
			if ((oddPoint>=records.length&&type==ODD)||(evenPoint>=records.length&&type==EVEN)) {
				break;
			}
			//判断开始打印偶数
			if (type==EVEN) {
				if (records[evenPoint]%2==0) {
					i++;
					writer.print(records[evenPoint]+",");
					writer.flush();
					//锁定全局变量方便线程输出后计数
					synchronized (lock) {
						count++;
						if (count%1000==0) {
							System.out.println("当前完成数量:"+count);
							if (count==10000) {
								System.out.println("Done!");
							}
						}
					}
				}
				//无论是否是偶数,打印成功一个后,偶数的起始位置都要后移
				evenPoint++;
			}else {
				//打印奇数
				if (records[oddPoint]%2==1) {
					i++;
					writer.print(records[oddPoint]+",");
					writer.flush();
					//锁定全局变量方便线程输出后计数
					synchronized (lock) {
						count++;
						if (count%1000==0) {
							System.out.println("当前完成数量:"+count);
							if (count==10000) {
								System.out.println("Done!");
							}
						}
					}
				}
				//无论是否是奇数,打印成功一个后,偶数的起始位置都要后移
				oddPoint++;
			}
			
		}
		type=~type;//切换打印类型
		notifyAll();//一组中的任一线程打印完后唤醒另一个线程
		try {
			wait();//释放锁进入等待状态,等待另一线程打印
		} catch (Exception e) {
			// TODO: handle exception
		}
		return false;
	}
} 


发表于 2016-03-19 00:04:25 回复(9)
网易笔试估计过不去了。。。
 
发表于 2016-03-21 19:05:04 回复(6)
package interviewquestion;

import java.io.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public class WorkQueue {
private ConcurrentLinkedQueue oddQueue = new ConcurrentLinkedQueue();
private ConcurrentLinkedQueue evenQueue = new ConcurrentLinkedQueue();
private AtomicBoolean isClose = new AtomicBoolean(false);
private AtomicInteger workCount = new AtomicInteger(0);
private ExecutorService service;
private CountDownLatch latch;
private PrintWriter writer;
private int threads;
private int targets = 10000;
public WorkQueue(ExecutorService service, int threads, CountDownLatch latch) {
    this.service = service;
    this.threads = threads;
    this.latch = latch;
}
public void doWork() throws IOException {
    service.execute(new Producer());
    writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream("result.txt")));
    for(int i = 0; i < threads; i++) {
        Worker evenWorker = new Worker(evenQueue, true);
        Worker oddWorker = new Worker(oddQueue, false).setCoWorker(evenWorker);
        service.execute(evenWorker);
        service.execute(oddWorker);
    }
    /*用于模拟输入
    for(int i = 1; i <= targets; i++) {
        if(i % 2 == 0) {
            evenQueue.add(i);
        } else {
            oddQueue.add(i);
        }
    }*/
}
private void writeToFile(Integer integer) throws IOException {
    writer.print(integer.intValue() + "\n");
    int current = workCount.incrementAndGet();
    if(current % 1000 == 0) {
        System.out.println("当前完成数:" + current);
    }
    if(current >= targets) {
        isClose.set(true);
        System.out.println("done");
    }
}
public void close() {
    writer.flush();
    writer.close();
    service.shutdown();
}
private class Worker implements Runnable {
    private AtomicBoolean doWork;
    private Worker coWorker;
    private ConcurrentLinkedQueue works;
    public Worker(ConcurrentLinkedQueue works, boolean doWork) {
        this.doWork = new AtomicBoolean(doWork);
        this.works = works;
    }
    public boolean isClose() {
        return isClose.get() && works.isEmpty();
    }
    public Worker setCoWorker(Worker coWorker) {
        this.coWorker = coWorker;
        coWorker.coWorker = this;
        return this;
    } [@Override](/profile/992988) public void run() {
        try {
            while(!isClose()) {
                if(doWork.get()) {
                    for(int count = 0; count < 10 && !isClose();) {
                        Integer num = works.poll();
                        if(num != null) {
                            writeToFile(num);
                            count++;
                        }
                    }
                    doWork.set(false);
                    coWorker.doWork.set(true);
                }
            }
        } catch (Exception e) {} finally {
            latch.countDown();
        }
    }
}
public class Producer implements Runnable { [@Override](/profile/992988) public void run() {
        BufferedReader reader = null;
        try {
            reader  = new BufferedReader(new FileReader("input.txt"));
            String line = reader.readLine();
            int temp;
            for(String string : line.split(" ")) {
                temp = Integer.parseInt(string);
                if(temp % 2 == 0) {
                    evenQueue.add(temp);
                } else {
                    oddQueue.add(temp);
                }
            }
        } catch (Exception e) {}
        finally {
            if(reader != null) {
                try {
                    reader.close();
                } catch (Exception e) {}
            }
        }
    }
}
public static void main(String[] args) {
    int threads = 10;
    CountDownLatch latch = new CountDownLatch(threads);
    WorkQueue workQueue = null;
    try {
        ExecutorService executor = Executors.newFixedThreadPool(threads);
        workQueue = new WorkQueue(executor, threads, latch);
        workQueue.doWork();
        latch.await();
    } catch (Exception e) {}
    finally {
        if(workQueue != null) {
            workQueue.close();
        }
    }
}
}
编辑于 2017-12-16 16:21:27 回复(0)
package first;

import java.io.File;
import java.io.PrintWriter;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Scanner;

public class Solve
{

	public static void main(String[] args) throws Exception
	{
		URL url = CreateData.class.getResource("/data.txt");
		Scanner scanner = new Scanner(new File(url.toURI()));

		for (int i = 0; i < 10000; i++)
		{
			int data = Integer.parseInt(scanner.nextLine());
			if (data % 2 == 0)
			{
				Common.ou.add(data);
			} else
			{
				Common.ji.add(data);
			}
		}
		scanner.close();
		
		Thread[] threads =new Thread[10];
		
		for (int i = 0; i < 5; i++)
		{
			PrintWriter pw = new PrintWriter(new File("./data"+i+".txt"));
			Common common=new Common();
			threads[i*2] = new Thread(new WriterJi(pw,common));
			threads[i*2+1] = new Thread(new WriterOu(pw,common));
		}
		
		for (Thread thread : threads)
		{
			thread.start();
		}
		

	}
}

class Common
{
	//每组打印线程奇偶打印标志
	public volatile boolean isJi = false;
	
	private static int count = 0;
	public static Queue<Integer> ji = new ArrayDeque<>(10000);
	public static Queue<Integer> ou = new ArrayDeque<>(10000);
	
	public static synchronized Integer jiGet()
	{	
		inc();
		
		if (!ji.isEmpty())
		{
			return ji.poll();
		} else
		{
			return null;
		}
	}
	
	public static synchronized Integer ouGet()
	{
		inc();
				
		if (!ou.isEmpty())
		{
			return ou.poll();
		} else
		{
			return null;
		}
	}
	
	public static synchronized void inc()
	{
		if(++count %1000 ==0)
		{
			System.out.println(count);
		}
		
		if(count == 10000)
		{
			System.out.println("Done");
		}
	}
}

class WriterJi implements Runnable
{
	public PrintWriter pw;
	private int count = 0;
	private Common common;

	public WriterJi(PrintWriter pw,Common common)
	{
		this.pw = pw;
		this.common= common;
	}

	@Override
	public void run()
	{
		while (!Common.ji.isEmpty() || !Common.ou.isEmpty())
		{
			if (common.isJi == true)
			{
				while (++count <= 10)
				{
					Integer data =Common.jiGet();
					if(data != null)
					{
						pw.println(data);
					}
					else
					{
						break;
					}

				}
				pw.flush();
				count = 0;
				common.isJi = false;
			}
		}
	}
}

class WriterOu implements Runnable
{
	private PrintWriter pw;
	private int count = 0;
	private Common common;

	public WriterOu(PrintWriter pw,Common common)
	{
		this.pw = pw;
		this.common =common;
	}

	@Override
	public void run()
	{
		while (!Common.ji.isEmpty() || !Common.ou.isEmpty())
		{
			if (common.isJi == false)
			{
				while (++count <= 10)
				{
					Integer data =Common.ouGet();
					if(data != null)
					{
						pw.println(data);
					}
					else
					{
						break;
					}
				}
				pw.flush();
				count = 0;
				common.isJi = true;
			}
		}
	}
}


编辑于 2017-07-19 20:36:21 回复(0)



测试代码:

编辑于 2015-04-01 14:46:48 回复(0)

import java.io.*;
import java.util.Random;


public class multiThreadPrint {
    private static final String path = "E:\\JavaBook\\MyprojectTouTiao\\MyAlgorithms\\fileprint\\";
//一个文件中有10000个数,
// 用Java实现一个多线程程序将这个10000个数输出到5个不用文件中(不要求输出到每个文件中的数量相同)。
// 要求启动10个线程,两两一组,分为5组。
// 每组两个线程分别将文件中的奇数和偶数输出到该组对应的一个文件中,
// 需要偶数线程每打印10个偶数以后,就将奇数线程打印10个奇数,如此交替进行。
// 同时需要记录输出进度,每完成1000个数就在控制台中打印当前完成数量,
// 并在所有线程结束后,在控制台打印”Done”.
    public static void main(String[]args)
    {
        try {
            PrintWriter pw = new PrintWriter(new FileWriter(new File(path+"input.txt")),true);
            Random random = new Random();
            for(int i =0;i<10000;i++)
            {
                pw.print(Math.abs(random.nextInt())%100+" ");
            }
            pw.flush();
            pw.close();  //输出10000个数到文件中。

            BufferedReader reader = new BufferedReader(new FileReader(path+"input.txt"));
            String str = reader.readLine();
            reader.close();
            String []strs = str.split(" ");
            int j =0;
            for(int i=0;i<5;i++)
            {
                int []records = new int [2000];
                for(int k=0;k<2000;k++)
                {
                    records[k] = Integer.parseInt(strs[j]);
                    j++; //读入每一个字符。数字
                }
                PrintWriter writer = new PrintWriter(new FileWriter(new File(path+"output"+i+".txt")), true);
                myThreadGroup group = new myThreadGroup(records, writer);
                new Thread(group).start();
                new Thread(group).start();
            }

        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

}

class myThreadGroup implements Runnable{
    private static int count = 0;
    private static Object lock = new Object();
    public static final int EVEN = 0;
    public static final int ODD = -1;
    //myThreadGroup成员变量ODD应该是-1,代码的type=~type 0按位取反应该是-1;1的话break的条件不能成立,容易造成边界溢出
    //Exception in thread "Thread-3" java.lang.ArrayIndexOutOfBoundsException: 2000
    //    at InterviewDirectory.netEASe2017.myThreadGroup.print(multiThreadPrint.java:116)
    //    at InterviewDirectory.netEASe2017.myThreadGroup.run(multiThreadPrint.java:83)
    //    at java.lang.Thread.run(Thread.java:748)
    private int type;
    private int records[];
    private PrintWriter writer;
    private int oddPoint = 0;
    private int evenPoint = 0;


    public myThreadGroup(int [] records, PrintWriter writer) {
        this.records = records;
        this.writer = writer;
        this.type = EVEN;
    }

    public void run()
    {
        while (print());  //两个线程进来之后会一直循环,直到循环输出2000个数字为止。
    }

    private synchronized boolean print() {
        for(int i =0;i<10;)
        {
            if(oddPoint>=records.length&&evenPoint>=records.length)
            {
                notifyAll();
                return false;
            }
            if((oddPoint>=records.length&&type==ODD)||(evenPoint>=records.length&&type==EVEN))
                break;
            if(type==EVEN)
            {
                if(records[evenPoint]%2==0)
                {
                    i++;
                    writer.print(records[evenPoint]+" ");
                    writer.flush();
                    synchronized (lock)
                    {
                        count++;
                        if(count%1000==0)
                        {
                            System.out.println("当前完成量:"+count);
                            if(count==10000)
                                System.out.println("Done!");
                        }
                    }
                }
                evenPoint++;
            }else {
                if(records[oddPoint]%2==1)
                {
                    i++;
                    writer.print(records[oddPoint]+" ");
                    writer.flush();
                    synchronized (lock)
                    {
                        count++;
                        if(count%1000==0)
                        {
                            System.out.println("当前完成量:"+ count);
                            if(count==10000)
                            {
                                System.out.println("Done!");
                            }
                        }
                    }
                }
                oddPoint++;
            }
        }
        type=~type;
        notifyAll();
        try {
            wait();
        }catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        return true;
    }


}
发表于 2018-05-11 15:49:46 回复(0)
很多答案结果展示的不够完整,本人认为总共10000个数同步的分别放入多个文件是很重要的一点,这里是双线程,第一个跑了5037,第二个跑了4963.。。。我看很多代码符合题意,但不是等于题意,是题意所述情况的一个特殊情况。




package java_offer;


import java.io.BufferedWriter;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.OutputStreamWriter;


publicclass Q22 {

public Integer sum = 10000;

public Object lock=new Object();

boolean[]  light = {true,true};


public static void open(Q22 c,String addr,String addr2){

odd od1 = c.new odd();

even ev1 = c.new even();

od1.setsDestFile(addr);

ev1.setsDestFile(addr);

od1.setTag("odd"+" "+"tag1");

ev1.setTag("even"+" "+"tag1");

odd od2 = c.new odd();

even ev2 = c.new even();

od2.setsDestFile(addr2);

ev2.setsDestFile(addr2);

od2.setTag("odd"+" "+"tag2");

ev2.setTag("even"+" "+"tag2");

od1.id = 0;

od2.id = 1;

ev1.id = 0;

ev2.id = 1;

od1.start();

od2.start();

ev1.start();

ev2.start();

}

public static void main(String[] args) throws IOException{


Q22 c = new Q22();

open(c,"./data/1.txt","./data/2.txt");




}

publicstaticsynchronizedvoid writeByFileOutputStream (String _sDestFile,


String _sContent) throws IOException {


FileOutputStream fos = null;

File destFile = new File(_sDestFile);


BufferedWriter out = null;

try {

out = new BufferedWriter(new OutputStreamWriter(

new FileOutputStream(destFile, true)));

out.write(_sContent+"\r\n");

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

out.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

class odd extends Thread{


String sDestFile;

String tag;

int id;

public String getTag() {

return tag ;

}

public void setTag(String tag) {

this.tag = tag;

}

public String getsDestFile() {

return sDestFile;

}

public void setsDestFile(String sDestFile) {

this.sDestFile = sDestFile;

}

int num = 10;

@Override

publicvoid run () {

// TODO Auto-generated method stub

while(true){

synchronized( lock ){

if(sum<=0){

break;

}

else if(light[id]){

StringBuffer sb = new StringBuffer();

if(sum%1000 == 0){

System.out.println((10000-sum) + " has been done!");

}

sb.append(sum--);

sb.append(tag);

try {

writeByFileOutputStream(sDestFile, sb.toString());

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

if(--this.num == 0 ){

light[id] = false;

this.num = 10;

lock.notifyAll();

try {

Thread.sleep(10);

lock.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

else if(!light[id]){

lock.notifyAll();

try {

Thread.sleep(10);

lock.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

}

}


class even extends Thread{


String sDestFile;

String tag;

int id;

public String getTag() {

return tag ;

}

public void setTag(String tag) {

this.tag = tag;

}

public String getsDestFile() {

return sDestFile;

}

public void setsDestFile(String sDestFile) {

this.sDestFile = sDestFile;

}

int num = 10;

@Override

publicvoid run () {

// TODO Auto-generated method stub

while(true){

synchronized( lock ){

if(sum<=0){

break;

}

else if(!light[id]){

StringBuffer sb = new StringBuffer();

if(sum%1000 == 0){

System.out.println((10000-sum) + " has been done!");

}

sb.append(sum--);

sb.append(tag);

try {

writeByFileOutputStream(sDestFile, sb.toString());

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

if(--this.num == 0 ){

light[id] = true;

this.num = 10;

lock.notifyAll();

try {

Thread.sleep(10);

lock.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

else if(!light[id]){

lock.notifyAll();

try {

Thread.sleep(10);

lock.wait();

} catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}

}

}

}

发表于 2017-02-20 14:00:27 回复(1)
package com.sort.main;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

public class ThreadFileDemo {
	public static void main(String[] args){
		String filename = "a.txt";
		String toFile = "b.txt";
		PrintWriter print = null;
		FileWriter fw = null;
		List<Integer> data = new ArrayList<Integer>();
//		产生随机数
		for(int i = 0; i < 10000; i++){
			data.add((int)(Math.random() * 1000));
		}
		
//		写入文件
		try {
			fw = new FileWriter(filename);
			fw.write(data.toString());
			fw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		try {
			print = new PrintWriter(new FileWriter(toFile));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		String str = data.toString().substring(1, data.toString().length() - 1);
		
		NumResource r = new NumResource(str.split(", "), print);
		ThreadOdd odd = new ThreadOdd(r);
		ThreadEven even = new ThreadEven(r);
		Thread t1 = new Thread(odd);
		Thread t2 = new Thread(odd);
		Thread t3 = new Thread(odd);
		Thread t4 = new Thread(odd);
		Thread t5 = new Thread(odd);
		Thread t6 = new Thread(even);
		Thread t7 = new Thread(even);
		Thread t8 = new Thread(even);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
		t6.start();
		t7.start();
		t8.start();
	}
}

class NumResource{
	public String[] str;
	public int count;
	public int o;
	public int e;
	public int s;
	public boolean flag = false;
	public PrintWriter print = null;
	public NumResource(String[] str, PrintWriter print){
		this.str = str;
		this.print = print;
		count = str.length;
	}
	
//	奇数计数
	public synchronized void odd(){
		while(flag){
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for(int i = 0; i < 10;){
			if(s >= count){
				if(print != null){
					print.close();
				}
				System.out.println("Done");
				System.exit(0);
			}
//			如果奇数打印完毕,直接跳出
			if(o >= count){
				break;
			}
			if(Integer.parseInt(str[o]) % 2 != 0){
				i++;
//				System.out.println("奇数:" + str[o] + "-" + s);
				print.write(str[o] + "\n");
				print.flush();
				printCount(o);
			}
			o++;
		}
		flag = true;
		notifyAll();

	}
	
//	偶数计数
	public synchronized void even(){
		while(!flag){
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for(int i = 0; i < 10;){
//			结束关闭流,退出
			if(s >= count){
				if(print != null){
					print.close();
				}
				System.out.println("Done");
				System.exit(0);
			}
//			如果偶数打印完毕,直接跳出
			if(e >= count){
				break;
			}
			if(Integer.parseInt(str[e]) % 2 == 0){
				i++;
//				System.out.println("偶数:" + str[e] + "-" + s);
				print.write(str[e] + "\n");
				print.flush();
				printCount(e);
			}
			e++;
		}
		flag = false;
		notifyAll();
	}
	
	public synchronized void printCount(int n){
		s++;
		if(s % 1000 == 0){
			System.out.println(Thread.currentThread().getName() + "完成打印个数:"+ s);
		}
	}
}

class ThreadOdd implements Runnable{
	private NumResource r;
	ThreadOdd(NumResource r){
		this.r = r;
	}

	@Override
	public void run() {
		while(true)
		{
			r.odd();
		}
	}
}

class ThreadEven implements Runnable{
	private NumResource r;
	ThreadEven(NumResource r){
		this.r = r;
	}

	@Override
	public void run() {
		while(true)
		{
			r.even();
		}
	}
}





发表于 2016-08-23 12:55:08 回复(0)
package Chapter1;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

public class Main03 
{
    public static void main(String ...args) throws Exception
    {
    	Main03 ob = new Main03();
    	ob.prepareTest();
    	BufferedReader br = new BufferedReader(new FileReader("E:/input.txt"));
    	String str = br.readLine();
    	br.close();
    	String[] tokens = str.split(" ");
    	
    	for(int i = 0;i < 5;i++)
    	{
    		int[] records = new int[2000];
    		PrintWriter pw = new PrintWriter(new FileWriter("E:/output" + i + ".txt"));
    		for(int j = 0;j < 2000;j++)
    		{
    			records[j] = Integer.parseInt(tokens[i*2000 + j]);
    		}
    		ThreadGroup tg = new ThreadGroup(pw,records);
    		new Thread(tg).start();
    		new Thread(tg).start();
    	}
    }
    
    private void prepareTest()
    {
        File inputFile = new File("E:/input.txt");
        FileWriter f = null;
        PrintWriter pw = null;
        try
        {
        	f = new FileWriter(inputFile);
        	pw = new PrintWriter(f);
        	for(int i = 0;i < 10000;i++)
        	{
        		pw.write(i + " ");
        	}
        	pw.flush();
        }
        catch(IOException ioe)
        {
        	ioe.printStackTrace();
        }
        finally
        {
        	if(f != null && pw != null)
        	{
        	try
        	{
        		f.close();
        		pw.close();
        	}
        	catch(Exception e)
        	{
        		e.printStackTrace();
        	}
        	}
        }
    }
}

class ThreadGroup implements Runnable
{
	//10 threads shared
	private static AtomicInteger totalNumbers = new AtomicInteger(0);
	
	//2 threads in the same group shared
	private PrintWriter pw;
	private ReentrantLock groupLock = new ReentrantLock();
	private volatile int type = 0;        //0 for even thread,-1 for odd thread
	private int oddPoint = 0;
	private int evenPoint = 0;
	private int[] toPrint;
	
	public ThreadGroup(PrintWriter writer,int[] numbers)
	{
		pw = writer;
		toPrint = numbers;
	}
	
	@Override
	public void run()
	{
		try {
			while(doPrint());
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private boolean doPrint() throws InterruptedException
	{
		try
		{
		    groupLock.lock();
		    //print 10 numbers
		    int recordsNum = toPrint.length;
		    for(int i = 0;i < 10;i++)
		    {
		    	if(evenPoint >= recordsNum && oddPoint >= recordsNum)
		    	{
		    		return false;
		    	}
		    	if(evenPoint >= recordsNum && type == 0 || oddPoint >= recordsNum && type == 1)
		    		break;
		    	//print even numbers
		    	if(type == 0)
		    	{
		    		while(evenPoint < recordsNum && toPrint[evenPoint] %2 != 0)
		    			evenPoint ++;
		    		if(evenPoint >= recordsNum)
		    		{
                        break;
		    		}
		    		pw.write(toPrint[evenPoint] + ",");
		    		evenPoint++;
		    		pw.flush();
		    		int number = totalNumbers.incrementAndGet();
		    		if(number % 1000 == 0)
		    			System.out.println("Processed " + number + " tokens!");
		    	}
		    	else
		    	{
		    		while(oddPoint < recordsNum && toPrint[oddPoint] %2 == 0)
		    			oddPoint ++;
		    		if(oddPoint >= recordsNum)
		    		{
                        break;
		    		}
		    		pw.write(toPrint[oddPoint] + ",");
		    		oddPoint++;
		    		pw.flush();
		    		int number = totalNumbers.incrementAndGet();
		    		if(number % 1000 == 0)
		    			System.out.println("Processed " + number + " tokens!");
		    	}
		    }
		    type = ~type;
		    return true;
		}
		finally
		{
			groupLock.unlock();
		}
		}
	}
感觉这个题目好绕,我来个抛砖引玉吧~~
以上代码只做了简单的测试,不保证正确。
看到题目,首先想到的是把数据均分为5组,然后每组里面奇偶线程交替打印。要注意的是10个线程互斥访问总的计数器,并且每组里面的两个线程使用的是同一个流,所以要进行同步;简单写了一个,效率什么的肯定不行,主要是思路拿出来让大神们指点一下。

另外,其实题目并没有要求把数据平均地打印到5个输出文件中,所以感觉应该可以用forkjoin线程池来做,不过同一个组里面奇偶线程同步访问的问题是绕不开的,这个应该也是主要出错的地方。

发表于 2016-08-02 16:39:14 回复(0)
package thread;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class FileMultiThread {

    private static final CountDownLatch door = new CountDownLatch(10); //同步工具类,可以确保n个线程的同步
    
    public static void main(String[] args) {
    
        FileMultiThread fmt = new FileMultiThread();
        try {
            PrintWriter writer = new PrintWriter(new FileWriter("F:\\number.txt"));
            Random random = new Random();
            for(int i = 0; i < 10000; i++){
                writer.print(random.nextInt(10000)+",");
            }
            writer.flush();
            writer.close();
            BufferedReader reader = new BufferedReader(new FileReader("F:\\number.txt"));
            String numberString = reader.readLine();
            reader.close();
            String[] strArrays = numberString.split(",");
            int step = 2000;
            
            for(int i = 0; i < 5; i++){
                int from = i * step;
                int to = (i + 1) * step;
                String[] records = Arrays.copyOfRange(strArrays, from, to);   //复制数组,有范围的复制,范围 from <= x < to
                PrintWriter pw = new PrintWriter(new FileWriter("F:\\test"+ i + ".txt"));
//                PrintWriter pw1 = new PrintWriter(new BufferedWriter(
//                        new OutputStreamWriter(new FileOutputStream("F:\\summary.txt"),"GBK")));
                
                final outPutToFile opt = new outPutToFile(pw, records); //虽然五次循环下的CopyOfPrintTest1
                                                 //对象的名称相同,但因为五个对象的内容不同,所以这五个对象的引用是不同的,所以jvm在内存中
                                                 //会开辟五个独立的内存用来分别存储对象
                fmt.odd(opt);
                fmt.even(opt);
            } //for结束
            door.await(); //通过使用CountDownLatch来实现10个线程的同步。通过调用await()方法可以在所有线程结束之后打印"Done"
                          //每当主线程获取时间片,准备打印“Done”时,都会因为十个子线程尚未全部执行结束而被阻塞,直到十个子线程全部执行
                          //完毕(即死亡)而从改行恢复执行
            System.out.println("Done");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public void odd(final outPutToFile opt){
        
            new Thread(new Runnable(){
            @Override
            public void run() {
                    while(opt.printOdd()){
                    }
                    door.countDown();  //每当线程结束,便调用CountDownLatch类的方法countDown()减1,当减到
                                       //0时,即说明子线程全部执行结束,主线程可以执行下一步的代码
            }
        }).start();
    }
    
    public void even(final outPutToFile opt){
        
        new Thread(new Runnable(){
            @Override
            public void run() {
                    while(opt.printEven()){
                    }
                    door.countDown();
            }
        }).start();
    }
}

class outPutToFile{
    
    private PrintWriter out = null;
    private String[] records;
    private static int count = 0; //静态变量(一个类只有一个),用来记录有效的输出次数
    private boolean flag = true;  //全局变量,用来控制奇偶线程的执行,为true时,执行奇线程,为false时,执行偶线程
    
    private Lock lock = new ReentrantLock(); //奇偶线程共享同一把锁
    
    /**
     * 题目要求先打印10个奇数,再打印10个偶数,因此设置两个条件对象(更加灵活)。
     * oddCondition下有三种情况:
     *        1、当flag为false时,奇线程阻塞,偶线程执行;
     *        2、当flag为true,且打印了10个奇数时,则偶线程唤醒,奇线程阻塞,偶线程执行;
     *        3、当flag为true,但剩余奇数个数已不够时,则for循环结束,唤醒偶线程,继而当前线程结束
     * evenCondition下有三种情况:
     *        1、当flag为true时,偶线程阻塞,奇线程执行;
     *        2、当flag为false,且打印了10个偶数时,则奇线程唤醒,偶线程阻塞,奇线程执行;
     *        3、当flag为false,但剩余偶数个数已不够时,则for循环结束,唤醒奇线程,继而当前线程结束
     */
    private Condition oddCondition = lock.newCondition();  //条件对象之奇数对象
    private Condition evenCondition = lock.newCondition(); //条件对象之偶数对象
    
    /**
     * 问题:若数组中的2000个数,只有三个奇数,剩下的全是偶数,会发生什么情况?
     * 思考:奇线程很快就会结束,只剩下偶线程。这时,如果偶线程在打印10个偶数后,将自己阻塞并尝试唤醒奇线程,
     * 会发生什么?奇线程无法唤醒(已死亡),自己(偶线程)被阻塞,无法被唤醒,其任务永远无法继续下去,程序
     * 出错。
     * 设想:当奇/偶线程循环结束时,在另一个线程中使“阻塞自己,唤醒对方”的代码失效,一直循环执行,直到循环结束。
     * 方案:记录奇/偶线程的循环次数。以奇线程为例,在奇线程中判断wholeEvenStep的值是否小于数组的长度,若小于,则说明对
     * 方线程还没死亡,执行“阻塞自己,唤醒对方”的代码;否则,不执行,继续下一次循环。偶线程的操作同上。
     */
    private int wholeOddStep = 0; //用来记录奇线程执行的次数
    private int wholeEvenStep = 0; //用来记录偶线程执行的次数
    private static int array_length = 0;  //将数组的长度设置为静态变量
    
    public outPutToFile(PrintWriter out,String[] records){
        this.out = out;
        this.records = records;
        outPutToFile.array_length = records.length; //动态设置数组的长度
    }

    /**
     * 奇线程要执行的函数
     * @return
     */
    public boolean printOdd(){
        
        lock.lock(); //上锁,必须加上try/finally,以确保锁会被释放
        int oddStep = 0; //记录奇线程有效的打印次数
        boolean oddFlag = true; //设置函数返回值
        try {
            /**
             * 之前用的是if(!flag){oddCondition.await();} else{...} ... 的形式,
             * 这种用法的错误之处在于,当flag为false时,奇线程会进入阻塞状态;当其对应的偶线程将
             * flag的值修改为true,并且唤醒奇线程时。奇线程便从阻塞的地方醒来,继续执行。结果就是
             * 执行完if(...)中的代码后,并不会进入else中(虽然flag已为true),而是进行else
             * 之后的代码。错误由此产生。
             * 使用while(!flag){...}循环的好处在于,当奇线程从阻塞的地方醒来后,将继续循环执行,
             * 如此,偶线程修改后的flag便会被检测出已为true,不符合当前条件,循环结束,进入之后真正
             * 要执行的代码
             */
            while(!flag){   
                oddCondition.await();
            }
            for(int i = 0; i < array_length; i++){
                wholeOddStep = i;
                int num = Integer.parseInt(records[i]);
                if(num % 2 == 1){  //如果是奇数,则打印
                    out.print(num+",");
                    out.flush();
                    synchronized (outPutToFile.class) { //10个线程共用一个count,必须加锁保护,使其原子操作
                        count++;
                        if(count % 1000 == 0){ //每当打印1000个数时,则提示当前的数量
                            System.out.println("当前完成数量:" + count);
                        }
                    }
                    oddStep++; //加1
                    if((wholeEvenStep + 1) < array_length){ //奇线程若未死亡,则执行以下代码,否则不执行
                        if(oddStep % 10 == 0){  //每打印10个奇数,则唤醒偶线程,并阻塞自己
                            flag = false;
                            evenCondition.signal();
                            oddCondition.await();
                        }
                    }
                }
            }
            flag = false;
            evenCondition.signal(); //循环正常结束后,唤醒偶线程
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
        oddFlag = false; //如果printOdd()执行结束,则说明调用这个方法的线程也即将结束
        closeOut(wholeEvenStep,wholeOddStep);
        return oddFlag;
    }
    
    /**
     * 如果奇偶线程均执行完,则关闭输出流
     * @param wholeEvenStep
     * @param wholeOddStep
     */
    public void closeOut(int wholeEvenStep,int wholeOddStep){
        
        if((wholeEvenStep == array_length) && (wholeOddStep == array_length)){
            out.close();
        }
    }
    
    /**
     * 偶线程调用的方法
     * @return
     */
    public boolean printEven(){
        
        lock.lock();
        int evenStep = 0;
        boolean evenFlag = true;
        try {
            while(flag){
                evenCondition.await();
            }
            for(int i = 0; i < array_length; i++){
                wholeEvenStep = i;
                int num = Integer.parseInt(records[i]);
                if(num % 2 == 0){
                    out.print(num+",");
                    out.flush();
                    synchronized (outPutToFile.class) {
                        count++;
                        if(count % 1000 == 0){
                            System.out.println("当前完成数量:" + count);
                        }
                    }
                    evenStep++;
                    if((wholeOddStep + 1) < array_length){
                        if(evenStep % 10 == 0){
                            flag = true;
                            oddCondition.signal();
                            evenCondition.await();
                        }
                    }
                }
            }
            flag = true;
            oddCondition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            lock.unlock();
        }
        evenFlag = false; //如果printEven()执行结束,则说明调用这个方法的线程也即将结束
        closeOut(wholeEvenStep,wholeOddStep);
        return evenFlag;
    }
}


发表于 2016-07-19 19:52:31 回复(0)
qi3头像 qi3
package thread;

import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileReader;
import java.io.FileWriter; 
import java.io.IOException; 
import java.io.PushbackReader; 
import java.nio.CharBuffer; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Iterator;
import java.util.List; 
import java.util.concurrent.CopyOnWriteArrayList; 
public class FileTest { 
    public static void main(String[] args) { 
        File file=new File("D:"+File.separator+"text.txt");         
        if(file.length()<Integer.MAX_VALUE){ 
            System.out.println("文件内容长度过大!"); 
            return;
         } 
        char[] charBuffer=new char[(int) file.length()]; 
        FileReader fileReader; 
        try { 
            fileReader = new FileReader(file);
            fileReader.read(charBuffer);
         } catch (FileNotFoundException e) { 
                e.printStackTrace(); 
         }catch (IOException e) { 
                e.printStackTrace(); 
         } 
        List<Integer> list=getNumber(charBuffer); 
        for(int i=0;i&lt;5;i++){ 
            File fileIn=new File("D:"+File.separator+"in"+(i+1)+".txt"); 
            if(!fileIn.exists()){ 
                 try { fileIn.createNewFile(); } catch (IOException e) { 
                    e.printStackTrace(); } 
            }
            try{ 
                FileWriter fileWriter=new FileWriter(fileIn,true); 
                PrintNum p=new PrintNum(list, fileWriter); 
                Runnable even=new evenThread(p); 
                Runnable odd=new oddThread(p); 
                Thread t1=new Thread(even); 
                Thread t2=new Thread(odd); t1.start(); t2.start(); 
             } catch (IOException e) { 
                e.printStackTrace(); } } 
            try { Thread.sleep(2000); } catch (InterruptedException e) {                 e.printStackTrace(); } 
            System.out.println("Done!");
    } 
    public static List<Integer> getNumber(char[] list){ 
        List<Integer> result=new ArrayList<Integer>(); 
        Character a=null; 
        String a1=""; 
        for(int i=0;i<list.length;i++){ 
            if(list[i]!=' '){ 
                if(list[i]=='-'){ a1="-"; } 
                else{ a1=a1+(list[i]-'0'); } 
            } else{ 
                if(a1!=""){ 
                     result.add(Integer.valueOf(a1)); a1=""; 
                 }
            } 
        }
        if(a1!=""){ 
            result.add(Integer.valueOf(a1)); a1=""; 
        } 
         return result; 
    } 
class PrintNum{ 
    private List<Integer> list; 
    private FileWriter fileWriter;  
    private int printEven=0; 
    private int printOdd=10; 

    public PrintNum(List<Integer> list,FileWriter fileWriter){
        this.list=list; 
        this.fileWriter=fileWriter; } 
    public void printEven() throws IOException{ 
        synchronized(fileWriter){ 
            while(list.size()>0){ 
                while(printEven>=10){ 
                    try { 
                        fileWriter.wait(); 
                    } catch (InterruptedException e) { /
                        e.printStackTrace(); } 
                }
                while(printEven<10){ 
                    printNumber(true);
                    try { 
                        Thread.sleep(10); 
                    } catch (InterruptedException e) { 
                        e.printStackTrace(); 
                    } 
                    printEven++; 
                } 
                printOdd=0; 
                fileWriter.notifyAll(); 
            }
        }
    } 
    public void printOdd() throws IOException{ 
        synchronized(fileWriter){
            while(list.size()>0){
                while(printOdd>=10){ 
                    try { 
                        fileWriter.wait();
                    } catch (InterruptedException e) { 
                        e.printStackTrace(); }
                    } 
                while(printOdd<10){ 
                    printNumber(false); 
                    try {   
                        Thread.sleep(10); 
                    } catch (InterruptedException e) { 
                        e.printStackTrace(); 
                    } 
                    printOdd++; 
                } 
                printEven=0; 
                fileWriter.notifyAll(); 
             } 
        }
    } 
    private void printNumber(boolean even) throws IOException{ 
        boolean done=false; 
        int i=0;
        synchronized (list) { 
            while(i&lt;list.size() && !done){ 
                if(even==true && Math.abs(list.get(i))%2==0){ 
                    String temp=list.get(i).toString()+" ";                     fileWriter.write(temp,0,temp.length()); 
                    fileWriter.flush();                         
                    Iterator<Integer> iter=list.iterator(); 
                    for(int k=0;k<=i;k++){ iter.next(); }
                    iter.remove(); 
                    done=true; } 
                else if(even==false && Math.abs(list.get(i))%2==1){ 
                    String temp=list.get(i).toString()+" ";                     fileWriter.write(temp,0,temp.length()); 
                    fileWriter.flush(); 
                    Iterator<Integer> iter=list.iterator(); 
                    for(int k=0;k<=i;k++){ iter.next(); } 
                    iter.remove(); 
                    done=true; 
                } 
                else{ i++; } 
            }
        }
    }
class evenThread implements Runnable { 
    private PrintNum p; 
    public evenThread(PrintNum p){ this.p=p; } 
    public void run() { 
        try { p.printEven(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
    }
class oddThread implements Runnable { 
    private PrintNum p; 
    public oddThread(PrintNum p){ this.p=p; }
    public void run() { 
        try { p.printOdd(); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        }
    }
}
编辑于 2015-08-28 19:26:40 回复(0)