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

现有的程序代码模拟产生了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();
        }
    }
}
其实就是生成一条花一秒,然后再去生成下个日志。
演示:
【Java多线程与并发库】18.java线程面试题1_第1张图片

我们下面来改造这段代码,使得只需四秒就打印完。
这是我自己写的答案:
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();
        }
    }
    
}
结果:
【Java多线程与并发库】18.java线程面试题1_第2张图片

我创建了容量为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 queue=new ArrayBlockingQueue(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();
        }
    }
    
}
效果:
【Java多线程与并发库】18.java线程面试题1_第3张图片

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

你可能感兴趣的:(Java线程与并发,Java多线程与并发库)