【java并发】一道多线程问题

本文介绍了一种利用多线程提高日志处理效率的方法。通过两种不同的逻辑设计思路,一是采用阻塞队列分离日志生产和消费过程,二是直接通过线程池处理日志,实现了16条日志能在4秒内完成打印的目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述: 
模拟一个场景:处理16条日志记录,每条日志记录打印时间需要1秒,正常情况下如果将这16条记录去部打完需要16秒,现在为了提高效率,准备开启4个线程去打印,4秒钟打印完,实现这个demo。

先来分析一下这个题目,关于这16条日志记录,我们可以在主线程中产生出来,这没用什么难度,关键是开启4个线程去执行,现在有两种思路:一种是日志的产生和打印日志的线程在逻辑上分开;一种是日志的产生和打印日志的线程在逻辑上不是分开的。这样说可能有点晦涩,下面我针对这两种思路,写个实现的demo就好理解了。

思路一:日志产生和日志打印在逻辑上是分开的。 

这相当于两条战线: 一条战线在不停的产生日志,另一个战线在不停的打印日志。很明显会想到阻塞队列的使用,产生日志不停的往阻塞队列中塞,打印日志不停的从阻塞队列中取,阻塞队列的大小可以自己设置,可以设置16个,也可以设置为1个,这都不影响执行。所以会用到BlockingQueue,下面看一下实现的demo:

public class QuestionOne {

    public static void main(String[] args) {
        //定义一个阻塞队列,队列大小可以装16个信息
        BlockingQueue<String> queue = new ArrayBlockingQueue<String>(16);

        for(int i = 0; i < 4; i ++) { //开启四个线程去阻塞队列中取日志打印
            new Thread(new Runnable() {

                @Override
                public void run() {
                    while(true) {
                        try {
                            String log = queue.take();  //取日志
                            parseLog(log); //打印日志
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }

        System.out.println("begin:" + (System.currentTimeMillis()/1000));

        for(int i = 0; i < 16; i ++) {
            final String log = "" + (i+1); //表示一个日志
            try {
                queue.put(log); //将产生的日志塞到阻塞队列中去
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

    public static void parseLog(String log) { //打印日志的方法
        System.out.println(Thread.currentThread().getName() + "---"
                + log + "---" + (System.currentTimeMillis()/1000));
        try {
            Thread.sleep(1000); //模拟打印一次日志需要1秒
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

这就好比一个系统正在运作,一边不停的产生日志,一边在不停的开启多个线程去打印日志信息,这个demo就写好了,运行结果就不贴了。

思路二:日志产生和日志打印在逻辑上不是分开的。

public class QuestionOnePool {

    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(4);//创建一个线程池
        System.out.println("begin:" + (System.currentTimeMillis()/1000));

        for(int i = 0; i < 16; i ++) {
            final String log = "" + (i+1); //表示一个日志
            service.execute(new Runnable() { //拿一个线程去执行

                @Override
                public void run() {
                    parseLog(log);
                }
            });
        }
        service.shutdown(); //最后别忘了关掉线程池

    }

    public static void parseLog(String log) {
        System.out.println(Thread.currentThread().getName() + "--开始打印-"
                + log + "---" + (System.currentTimeMillis()/1000));
        try {
            Thread.sleep(1000); //模拟打印一次日志需要1秒
            System.out.println(Thread.currentThread().getName() + "--结束打印-"
                    + log + "---" + (System.currentTimeMillis()/1000));
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

转载于:https://my.oschina.net/wugong/blog/1630756

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值