关于多线程练习的几个题目
第一题:现有的程序代码模拟产生了16个日志对象,并且需要运行16秒才能打印完这些日志,请在程序中增加4个线程去调用parseLog()方法来分头打印这16个日志对象,程序只需要运行4秒即可打印完这些日志对象。原始代码如下:
交给四个线程,打印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()方法去进行处理,故每个消费者都需要一秒才能处理完,程序应保证这些消费者线程依次有序地消费数据,只有上一个消费者消费完后,下一个消费者才能消费数据,下一个消费者是谁都可以,但要保证这些消费者线程拿到的数据是有顺序的。原始代码如下:
解答:
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 }
行走在设计师的路上!