前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一起聊聊3个线程依次打印1、2、3...的故事

一起聊聊3个线程依次打印1、2、3...的故事

作者头像
luoxn28
发布2020-03-10 15:32:35
1.2K0
发布2020-03-10 15:32:35
举报
文章被收录于专栏:TopCoder

3个线程依次打印1、2、3…这个问题,常常被作为面试题,题目如下:

三个线程,一个线程负责打印1,4,7,……;第二个负责打印2,5,8,……,第三个负责打印3,6,9,……,要求在控制台中按顺序输出1,2,3,4,5,6……。

这个题目肯定是要启动3个线程的,那怎么让这3个线程“协作”按顺序打印1、2、3呢?从大的方面来讲,这种“协作”可分为以下两种:

  • 竞争型:每个线程都抢着去打印,如果发现不该自己打印,则准备下一轮抢。由于大家都是竞争的,因此需要用锁机制来保护。
  • 协同型:当前线程线程打印之后通知下一个线程去打印,这种需要确认好第一个线程打印时机。由于是协同型的因此可以不用锁机制来保护,但是需要一个通知机制。

竞争型打印

多个线程竞争型打印,优势是代码简单易懂,劣势是线程争抢是CPU调度进行的,可能该某个线程打印时结果该线程迟迟未被CPU调度,结果其他线程被CPU调度到但是由于不能执行打印操作而继续争抢,造成CPU性能浪费。示例代码如下:

代码语言:javascript
复制
public class DemoTask implements Runnable {

    // 这里将lock对象换成 Lock(ReentrantLock) 进行lock/unlock也是可以的
    private static final Object lock = new Object();
    private static final int MAX = 1024;
    private static int current = 1;

    private int index;
    public DemoTask(int index) {
        this.index = index;
    }

    @Override
    public void run() {
        while (current <= MAX) {
            synchronized (lock) {
                if ((current <= MAX) && (current % 3 == index)) {
                    System.out.println(current++);
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {
        List<Thread> threadList = Arrays.asList(
                new Thread(new DemoTask(0)),
                new Thread(new DemoTask(1)),
                new Thread(new DemoTask(2))
        );

        threadList.forEach(Thread::start);
        for (Thread thread : threadList) {
            thread.join();
        }
    }
}

协同型打印

多个线程协同型打印,优势是各个线程使用“通知”机制进行协同分工,理论上执行效率较高,不过要使用对应的“通知”机制。关于如何“通知”,第一种是可使用Java对象的 wait/notify 或者Conditon对象的 await/signal ,第二种是以事件或者提交任务的方式(比如通过提交“待打印数字”这个任务给下一个线程)。

下面以第二种方式进行代码分析,比如当前线程通过submit给下一个线程一个“待打印数字”的任务,这样很容易想到使用只包含1个线程的线程池来实现,示例代码如下:

代码语言:javascript
复制
public class DemoTask implements Runnable {

    // 主线程要等待线程打印完毕,使用CountDownLatch通知机制
    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    private static List<ExecutorService> threadList = new ArrayList<>();
    private static final int MAX = 1024;
    private static int current = 1;

    @Override
    public void run() {
        if (current <= MAX) {
            System.out.println(current++);
            threadList.get(current % threadList.size()).submit(new DemoTask());
        } else {
            countDownLatch.countDown();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            threadList.add(Executors.newFixedThreadPool(1));
        }

        threadList.get(0).submit(new DemoTask());
        countDownLatch.await();
        threadList.forEach(ExecutorService::shutdown);
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-02-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 TopCoder 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 竞争型打印
  • 协同型打印
相关产品与服务
腾讯云代码分析
腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,助力维护团队卓越代码文化。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档