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

  前面几篇博文基本上总结了一下java并发里的一些内容,这篇博文主要从一个问题入手,看看都能用到前面总结的哪些并发技术去解决。

题目描述:

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

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

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

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

public class Practice1 {

    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就写好了,运行结果就不贴了。

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

  这种思路就是,我产生日志的同时,你就给我打印出来,四个线程一起干!那么这种思路的话,就得用到线程池了,我一开始创建一个线程池,里面装了4个线程,然后产生日志的时候,我让这个线程池拿线程去执行它即可。demo如下:

public class Practice1 {

    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秒
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

  关于这个问题,就总结到这吧,把这两种思路搞清楚一般就可以有效的解决了。

  

  相关阅读:http://blog.csdn.net/column/details/bingfa.html



—–乐于分享,共同进步!

—–更多文章请看:http://blog.csdn.net/eson_15

时间: 2024-08-25 16:55:02

【java并发】一道多线程问题的相关文章

Java 并发和多线程(一) Java并发性和多线程介绍[转]

作者:Jakob Jenkov 译者:Simon-SZ  校对:方腾飞 http://tutorials.jenkov.com/java-concurrency/index.html 在过去单CPU时代,单任务在一个时间点只能执行单一程序.之后发展到多任务阶段,计算机能在同一时间点并行执行多任务或多进程.虽然并不是真正意义上的“同一时间点”,而是多个任务或进程共享一个CPU,并交由操作系统来完成多任务间对CPU的运行切换,以使得每个任务都有机会获得一定的时间片运行. 随着多任务对软件开发者带来的

Java并发和多线程基础(一)

1.java线程状态 Java中的线程可以处于下列状态之一: NEW: 至今尚未启动的线程处于这种状态. RUNNABLE: 正在 Java 虚拟机中执行的线程处于这种状态. BLOCKED: 受阻塞并等待某个监视器锁的线程处于这种状态. WAITING: 无限期地等待另一个线程来执行某一特定操作的线程处于这种状态. TIMED_WAITING: 等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态. TERMINATED: 已退出的线程处于这种状态. 在给定时间点上,一个线程只能处于

Java并发和多线程2:3种方式实现数组求和

本篇演示3个数组求和的例子. 例子1:单线程例子2:多线程,同步求和(如果没有计算完成,会阻塞)例子3:多线程,异步求和(先累加已经完成的计算结果) 例子1-代码 package cn.fansunion.executorservice; public class BasicCaculator { public static long sum(int[] numbers){ long sum = 0; for(int i=0;i<numbers.length;i++){ sum += numbe

Java并发和多线程1:并发框架基本示例.txt

Executor框架是指java 5中引入的一系列并发库中与executor相关的一些功能类,其中包括ThreadPool,Executor,Executors,ExecutorService,CompletionService,Future,Callable等. 并发编程的一种编程方式是把任务拆分为一系列的小任务,即Runnable,然后在提交给一个Executor执行,Executor.execute(Runnalbe) .Executor在执行时使用内部的线程池完成操作.一.创建线程池Ex

1-3 Java并发与多线程基础

1.并发与多线程简介 最初计算机是单任务的,后来发展到可以并行运行多任务(进程),由操作系统来调度,每个任务可以获得一个时间片.多任务下,每个任务在使用系统资源结束后需要释放资源给其他任务. 后来,同一个任务内部发展出多个线程并发操作,会对相同的内存空间进行并发读写操作.更现代的计算机伴随着多核CPU的出现,也就意味着不同的线程能被不同的CPU核得到真正意义的并行执行.有些在多线程中出现的问题会和多任务以及分布式系统中出现的存在类似,因此该系列会将多任务和分布式系统方面作为参考,所以叫法上称为"

Java并发和多线程那些事儿

我记得我接触电脑的时候是在小学三年级的时候,那是1995年,那年发布了windows95,但是我学习的时候还是只是dos系统,简单对于文件的一些命令操作还有五笔 在过去的那个年代,电脑都是单CPU,也就是单任务处理:多任务处理到后来才慢慢发展起来,多任务代表电脑在同一时刻内可以处理很多并行操作,这样CPU被利用率高了,多个任务都可以共享.多任务处理的出现对于软件开发者来说需要做更多的事,就是资源释放,也就是垃圾回收,在软件不用的时候要释放资源,这样就可以给其他软件腾出资源来使用,就像ios内存机

Java并发和多线程(二)Executor框架

Executor框架 1.Task?Thread? 很多人在学习多线程这部分知识的时候,容易搞混两个概念:任务(task)和线程(thread). 并发编程可以使我们的程序可以划分为多个分离的.独立运行的任务.而这些任务具体得由线程来驱动.Java中,Thread类自身不执行任何操作,它只是驱动赋予它的任务,任务由Runnable接口提供. 2.executor Executor是个简单的接口,但它却提供了一种标准的方法将任务的提交过程与任务的执行过程解耦开来,从而无须太大困难就可以为某种类型的

java并发与多线程API学习

Executor接口 public interface Executor { void execute(Runnable command); } Executor接口中之定义了一个方法execute(Runnable command),该方法接收一个Runable实例,它用来执行一个任务,任务即一个实现了Runnable接口的类. 在Java 5之后,任务分两类:一类是实现了Runnable接口的类,一类是实现了Callable接口的类.两者都可以被ExecutorService执行,但是Run

JAVA并发七(多线程环境中安全使用集合API)

在集合API中,最初设计的Vector和Hashtable是多线程安全的.例如:对于Vector来说,用来添加和删除元素的方法是同步的.如果只有一个线程与Vector的实例交互,那么,要求获取和释放对象锁便是一种浪费,另外在不必要的时候如果滥用同步化,也有可能会带来死锁.因此,对于更改集合内容的方法,没有一个是同步化的.集合本质上是非多线程安全的,当多个线程与集合交互时,为了使它多线程安全,必须采取额外的措施. 在Collections类 中有多个静态方法,它们可以获取通过同步方法封装非同步集合

Java并发编程 - 多线程/并发面试题集合(持续更新)

1. 现在有线程T1.T2和T3.你如何确保T2线程在T1之后执行,并且T3线程在T2之后执行. https://www.cnblogs.com/helios-fz/p/11216925.html 2. Java 中新的Lock接口相对于同步代码块(synchronized block)有什么优势?如果让你实现一个高性能缓存,支持并发读取和单一写入,你如何保证数据完整性. Lock接口的最大优势是它为读和写提供两个单独的锁(ReentrantReadWriteLock),ReentrantRea