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

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

执行结果:

时间: 2024-11-11 19:12:27

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

多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify())

1.线程安全,无非就是加锁,访问共享资源时,synchronized 2.线程通信,就是控制各个线程之间的额执行顺序,线程之间是无法进行通讯的,也是借助于第三方object,object的wait()和notify()通讯 原文地址:https://www.cnblogs.com/panxuejun/p/8416546.html

有4个线程A、B、C、D,分别打印1、2、3、4,请同时启动他们,但是要求按照1234的顺序输出结果

1. 有4个线程A.B.C.D,分别打印1.2.3.4,请同时启动他们,但是要求按照1234的顺序输出结果. public class TestABCThread3 { private Object lock = new Object(); private int count; public static void main(String[] args) { TestABCThread3 abc = new TestABCThread3(); new Thread(abc.new Run("C&

QT多线程的简单使用,主线程发一份数据,子线程收两份数据

先看效果图,示例发送数据“Hello World” 主线程:0x16f54aeda20,另两个子线程分别是0x4f1baff690.0x4f1baff6a0 因为在子线程中加了200ms.400ms延迟,所以打印是有先后顺序的 核心代码也就一丢丢.代码逻辑就是使用信号与槽使用线程之间产生联系 1 MfBusiness::MfBusiness(QObject *parent) : QObject(parent) 2 { 3 connect(&se,&MfSendData::Sgl_Send,

线程系列04,传递数据给线程,线程命名,线程异常处理,线程池

本篇体验:如何传递数据给线程,如何给线程命名,线程的异常处理,线程池.实在是太基础的部分. □ 传递数据给线程 ※ 使用Lambda表达式 class Program { static void Main(string[] args) { Thread t = new Thread(() => Say("hello", "world")); t.Start(); } static void Say(string msg, string msg1) { Cons

【java并发】线程范围内共享数据

假设现在有个公共的变量data,有不同的线程都可以去操作它,如果在不同的线程对data操作完成后再去取这个data,那么肯定会出现线程间的数据混乱问题,因为A线程在取data数据前可能B线程又对其进行了修改,下面写个程序来说明一下该问题: public class ThreadScopeShareData { private static int data = 0;//公共的数据 public static void main(String[] args) { for(int i = 0; i

多线程-生产者与消费者(存储数据与打印数据)

无线程同步: 存储数据: 1 public class Storage { 2 int data; 3 4 public int getData() { 5 return data; 6 } 7 8 public void setData(int data) { 9 this.data = data; 10 } 11 12 } 产生数据: 1 public class Counter implements Runnable { 2 private Storage storage; 3 4 pub

async 与 await 线程调用顺序

用async做一个多线程下载并在datagridview中即时更新,运行时在达到4个线程同时下载时界面卡顿,多次尝试后是不知道async与await线程调用顺序造成. 进入async方法后在调用await之前代码都在主线程(调用线程)中运行,调用await时及之后的async方法代码将另起线程运行该部分代码,而主线程在遇到await后回到主线程继续执行async后的代码. 将async方法通过声明委托后用begininvoke调用后解决.

多个线程访问共享对象和数据的方式

多个线程访问共享对象和数据的方式有两种情况:1.每个线程执行的代码相同,例如,卖票:多个窗口同时卖这100张票,这100张票需要多个线程共享.2.每个线程执行的代码不同,例如:设计四个线程,其中两个线程每次对j增加1,另外两个线程每次对j减少1. a.如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个对象中有共享数据.卖票就可以这样做,每个窗口都在做卖票任务,卖的票都是同一个数据(点击查看具体案例). b.如果每个线程执行的代码不同,就需要使用不同的Runnable对象,有两种

关于for 循环里 线程执行顺序问题

最近在做项目时遇到了 这样的需求 要在一个for循环里执行下载的操作, 而且要等 下载完每个 再去接着走循环.上网查了一些 觉得说的不是很明确.现在把我用到的代码 贴上 希望可以帮到有此需求的开发者        private Handler mHandler = new Handler() {               public void handleMessage(android.os.Message msg) {                       switch (msg.