【Java多线程与并发库】18.java线程面试题1

来源:互联网 发布:头像psd源码 编辑:程序博客网 时间:2024/06/06 19:43
现有的程序代码模拟产生了16个日志对象,并且需要运行16秒才能打印完这些日志,请在程序
中增加4个线程去调用parseLog()方法来分头打印这16个日志对象,程序只需要运行4秒即可打印
玩这些日志对象。原始代码如下:
package cn.edu.hpu.test;public class ReadTest {    public static void main(String[] args) {        System.out.println("begin:"+(System.currentTimeMillis()/1000));        /*模拟处理16行日志,下面的代码产生了16条日志对象,         * 当前代码需要运行16秒才能打印完这些日志*/        for (int i = 0; i < 16; i++) {            final String log = ""+(i+1);//这行代码不能改动            {                ReadTest.parseLog(log);            }        }    }    //parseLog方法内的代码不能改动    private static void parseLog(String log) {        System.out.println(log+":"+(System.currentTimeMillis()/1000));        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}
其实就是生成一条花一秒,然后再去生成下个日志。
演示:


我们下面来改造这段代码,使得只需四秒就打印完。
这是我自己写的答案:
package cn.edu.hpu.test;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ReadTest {    public static void main(String[] args) {        ExecutorService executor=Executors.newFixedThreadPool(4);//创建容量为4的线程池        System.out.println("begin:"+(System.currentTimeMillis()/1000));        /*模拟处理16行日志,下面的代码产生了16条日志对象,         * 当前代码需要运行16秒才能打印完这些日志*/        for (int i = 0; i < 16; i++) {            final String log = ""+(i+1);//这行代码不能改动            {                executor.execute(new Runnable(){//每打印一次日志执行一个线程                    public void run() {                        ReadTest.parseLog(log);                    }                });            }        }    }    //parseLog方法内的代码不能改动    private static void parseLog(String log) {        System.out.println(log+":"+(System.currentTimeMillis()/1000));        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }    }
结果:


我创建了容量为4的线程池,然后每次打印的时候创建一个新的线程对象放进去,因为
容量为4,每次只有四个线程同时运行,所以每一秒钟完成四个,下四个线程进去继续运行,如此就实现了4秒打印16个日志的效果。

官方给的是使用阻塞队列来完成,其实同样,这个问题也可以这么解决:
package cn.edu.hpu.test;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;public class ReadTest {    public static void main(String[] args) {        final BlockingQueue<String> queue=new ArrayBlockingQueue<String>(4);//创建容量为4的阻塞队列                for (int i = 0; i < 4; i++) {            new Thread(new Runnable(){                //该线程等待打印,只要queue有数据,就立马开始打印                public void run() {                    String log=null;                    while(true){                        try {                            if(queue.size()>0){                                log=queue.take();                                ReadTest.parseLog(log);                            }                        } catch (InterruptedException e) {                            e.printStackTrace();                        }                    }                }                            }).start();        }                System.out.println("begin:"+(System.currentTimeMillis()/1000));        /*模拟处理16行日志,下面的代码产生了16条日志对象,         * 当前代码需要运行16秒才能打印完这些日志*/        for (int i = 0; i < 16; i++) {            final String log = ""+(i+1);//这行代码不能改动            {                try {                    queue.put(log);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }    //parseLog方法内的代码不能改动    private static void parseLog(String log) {        System.out.println(log+":"+(System.currentTimeMillis()/1000));        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }    }
效果:


总结一下,我个人认为官方的答案虽然也实现了这个效果,但是我认为有以下缺陷:
1.线程中有死循环,将会一直占用CPU的内存,这种做法不是很好。
2.线程打印出来的日志文件的顺序是乱序,在尚不知晓日志打印顺序对其它业务有何影响
的情况下,这种做法也不是很好。
3.代码量大,相比我使用线程池的做法,使用阻塞队列的代码量明显要大于我的代码量。
转载请注明出处:http://blog.csdn.net/acmman/article/details/53116117
0 0
原创粉丝点击