多个线程实现顺序打印数据,(可自定义线程一次打印数量和总数量)
最近看到一道面试题:让3个线程顺序打印数字,如线程1打印1-5,线程2打印6-10,线程3打印11-15,然后是线程1打印16-20...一直打印到75结束。
这到题主要问题有两点:
第一点是不能让线程打印的过程中出现其他线程
第二点是要实现线程进入的过程是有序的,如上123123..这样。
我先是把基本的功能实现了,后来发现可以改造一下,做成可扩展的,即每次打印的数量可自定义,总的数量可自定义,并且保证线程的顺序是有序的,下面是具体代码:
PrintQueue.java 文件,同步线程,控制打印顺序,也是最主要的方法
package com.cky; import java.util.LinkedHashMap; import java.util.Map; public class PrintQueue { public int targetNum=0; //要打印的目标数量 public int printOnce=0; //一次要打印的次数 private int nowNum=1; //目前打印到的数量 /** * * @param targetNum 要打印的目标数量 * @param printOnce 一次要打印的次数 */ public PrintQueue(int targetNum, int printOnce) { super(); this.targetNum = targetNum; this.printOnce = printOnce; } private int nextThreadNum=0;//下次要执行线程的下标 private int threadCount=0;//总的线程数量 //map集合,存放线程,键是具体线程,值存放线程打印的顺序 private Map<Thread,Integer> threads=new LinkedHashMap<Thread,Integer>(); //添加线程 public void setThread(Thread thread) { threads.put(thread, threadCount); threadCount++; } //运行线程 public void run() { for (Thread thread : threads.keySet()) { thread.start(); } } public synchronized void printNum() throws InterruptedException { //获取当前线程 Thread currentThread=Thread.currentThread(); //获取当前线程坐标 int currentNum=threads.get(currentThread); //判断是否为期望线程 if(currentNum==nextThreadNum) { for(int i=0;i<printOnce;i++) { System.out.println("当前线程:"+currentThread.getName()+":"+nowNum++); if(nowNum>targetNum) { System.out.println("工作完成"); this.wait(); } } //期望线程名+1 nextThreadNum=(++nextThreadNum)%threadCount; } } }
RunTest.java 很简单的Runable接口实现,功能就是请求打印
package com.cky; class RunTest implements Runnable{ PrintQueue ps; public RunTest(PrintQueue ps ) { this.ps=ps; } @Override public void run() { try { while(true) { ps.printNum(); } } catch (InterruptedException e) { e.printStackTrace(); } } }
ThreadDemo.java 测试类
package com.cky; public class ThreadDemo { public static void main(String [] args) { //设置一共打印20个,每个线程一次只打印3个
PrintQueue ps=new PrintQueue(20, 3);
//添加线程 ps.setThread(new Thread(new RunTest(ps),"王大锤")); ps.setThread(new Thread(new RunTest(ps),"张全蛋")); ps.setThread(new Thread(new RunTest(ps),"二狗")); ps.run(); } }
执行结果: