多个线程实现顺序打印数据,(可自定义线程一次打印数量和总数量)

  最近看到一道面试题:让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(); } }

执行结果:

 

posted @ 2017-12-01 23:33  宇的季节  阅读(3332)  评论(4编辑  收藏  举报