關於多線程練習的幾個題目


第一題:現有的程序代碼模擬產生了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     }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM