处理多线程问题,练手用
第一题:现有的程序代码模拟产生了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 }
行走在设计师的路上!