处理多线程问题,练手用

第一题:现有的程序代码模拟产生了16个日志对象,并且需要运行16秒才能打印完这些日志,请在程序中增加4个线程去调用parseLog()方法来分头打印这16个日志对象,程序只需要运行4秒即可打印完这些日志对象。原始代码如下:

多线程推理yolo multiprocessing_数据

交给四个线程,打印16个日志对象信息,启动四个线程容易,但是怎样将这16个日志对象交给4个线程,这时候我们用阻塞队列,将要打印的日志信息放到阻塞队列中,四个线程启动时都从阻塞队列中取数据,取完后打印即可。阻塞队列的大小可以自行设置。

修改为多线程打印日志信息后的代码及注释参考下文:

1 public class Test {
 2     public static void main(String[] args) {
 3         System.out.println("begin:" + (System.currentTimeMillis() / 1000)); 
 4         final BlockingQueue<String> queue = new ArrayBlockingQueue<String>(16);
 5         //启动4个线程
 6         for(int i = 0; i < 4; i++){
 7             new Thread(new Runnable(){
 8                 @Override
 9                 public void run() {
10                     //不断从阻塞队列中取出数据并打印
11                     while(true){
12                         String log;
13                         try {
14                             log = queue.take();
15                             parseLog(log);
16                         } catch (Exception e) {
17                             e.printStackTrace();
18                         }
19                     }
20                 }
21                 
22             }).start();
23         }
24         for (int i = 0; i < 16; i++) { // 这行代码不能改动
25             final String log = "" + (i + 1);// 这行代码不能改动,生成的日志信息
26             {
27                 try {
28                       queue.put(log);                //将日志信息放入阻塞队列
29                       //Test.parseLog(log);            //打印日志信息
30                 } catch (Exception e) {
31                     e.printStackTrace();
32                 }
33             }
34         }
35     }
36     // parseLog方法内部的代码不能改动
37     public static void parseLog(String log) {
38         System.out.println(log + ":" + (System.currentTimeMillis() / 1000));
39         try {
40             Thread.sleep(1000);
41         } catch (InterruptedException e) {
42             e.printStackTrace();
43         }
44     }
45 }

 

第二题:现成程序中的Test类中的代码在不断地产生数据,然后交给TestDo.doSome()方法去处理,就好像生产者在不断地产生数据,消费者在不断消费数据。请将程序改造成有10个线程来消费生成者产生的数据,这些消费者都调用TestDo.doSome()方法去进行处理,故每个消费者都需要一秒才能处理完,程序应保证这些消费者线程依次有序地消费数据,只有上一个消费者消费完后,下一个消费者才能消费数据,下一个消费者是谁都可以,但要保证这些消费者线程拿到的数据是有顺序的。原始代码如下:

多线程推理yolo multiprocessing_阻塞队列_02

解答:

10个线程,依次消费数据,仍然是将待消费数据放入阻塞队列,让10个线程去取数据消费,所不同的是这次消费必须一个一个线程来,而不再是10个线程一起去取,因此用到了线程的同步。同步方法有多种,这里使用Semaphore来进行线程间的同步,代码及注释如下:

1 public class Test {
 2     
 3         public static void main(String[] args) {
 4             
 5             final SynchronousQueue<String> queue = new SynchronousQueue<String>();
 6             final Semaphore semaphore = new Semaphore(1);
 7             //10个线程,分别消费数据,依旧是从阻塞队列中获取数据
 8             for(int i=0; i < 10; i++){
 9                 new Thread(new Runnable(){
10                     @Override
11                     public void run() {
12                         try {
13                             semaphore.acquire();
14                             String input = queue.take();
15                             String output = TestDo.doSome(input);
16                             System.out.println(Thread.currentThread().getName()+ ":" + output);
17                             semaphore.release();
18                         } catch (Exception e) {
19                             e.printStackTrace();
20                         }
21                     }
22                     
23                 }).start();
24             }
25             
26             System.out.println("begin:"+(System.currentTimeMillis()/1000));
27             for(int i=0;i<10;i++){  //这行不能改动
28                 String input = i+"";  //这行不能改动,不断产生数据
29                 try {
30                     queue.put(input);
31                 } catch (Exception e) {
32                     e.printStackTrace();
33                 }
34                 //String output = TestDo.doSome(input);//不断消费数据
35                 //System.out.println(Thread.currentThread().getName()+ ":" + output);
36             }
37         }
38     }

 

行走在设计师的路上!