線程的兩種實現方式,以及區別


-  讓類成為線程類有兩種方式,實現Runnable接口,以及繼承Thread類(類中實現了Runnable接口,還提供了一些額外的方法)。 

一、Runnable相對優勢:

  • java的單繼承,當繼承了Thread類,則不能繼承其他類,而實現Runnable接口可以

  • 實現Runnable接口的線程類的多個線程,可以訪問同一變量,而Thread則不能(多窗口買票問題)

原因:兩種方式啟動方式不同:

 

  • Runnable線程類是實例化一個對象o之后,通過多次new Thread(o).start();啟動多個線程,而這幾個線程屬於一個對象,對象的成員變量是同一個。
  • Thread線程類啟動多個線程需要 new MyThread().start();每個線程啟動都對應多個對象,他們的成員變量是獨立的。

 測試代碼如下:

(1)實現Runnable:

 1 package com.loan.entity;
 2  
 3 import lombok.Data;
 4  
 5 @Data
 6 public class Test2 implements Runnable{
 7 private int ticket=100;
 8 @Override
 9 public void run() {
10     // TODO Auto-generated method stub
11     while(true){
12         if(ticket>0){
13             System.out.println(Thread.currentThread().getName()+"...is saling,余票:"+ticket--);
14         }
15     }
16 }
17 public static void main(String[] args) {
18     Test2 t=new Test2();//只能使用同一個t
19     new Thread(t).start();
20     new Thread(t).start();
21     new Thread(t).start();
22     new Thread(t).start();
23 }
24 }

 

運行結果:

(2)繼承Thread

 1 package com.loan.entity;
 2  
 3 public class Test3 extends Thread{
 4     int ticket=100;
 5     public void run(){
 6         while(true){
 7             if(ticket>0){
 8                 System.out.println(Thread.currentThread().getName()+"...is saling,余票:"+ticket--);
 9             }
10         }
11     }
12     public static void main(String[] args) {
13         new Test3().start();
14         new Test3().start();
15         new Test3().start();
16         new Test3().start();
17     }
18 }

很明顯,上面這種方式是錯誤的!

繼承Thread類也可以通過內部類發方式實現。代碼如下:

 1 package com.loan.entity;
 2  
 3 public class Test3{
 4     private  int ticket=100;
 5     class InnerClass extends Thread{
 6         private Test3 t3;
 7         InnerClass(Test3 t){
 8             t3=t;
 9         }
10         public void run(){
11             while(true){
12                 if(ticket>0){
13                     ticket--;
14                     System.out.println(Thread.currentThread().getName()+"...is saling,余票:"+ticket);
15                 }
16             }
17         }
18     }
19     public static void main(String[] args) {
20         Test3 test3=new Test3();
21         Thread t1=test3.new InnerClass(test3);
22         Thread t2=test3.new InnerClass(test3);
23         Thread t3=test3.new InnerClass(test3);
24         Thread t4=test3.new InnerClass(test3);
25         t1.setName("t1");
26         t2.setName("t2");
27         t3.setName("t3");
28         t4.setName("t4");
29         t1.start();
30         t2.start();
31         t3.start();
32         t4.start();
33         }
34 }

 

運行結果:

二、Thread優勢

1、使用線程的方法方便一些,例如:獲取線程的Id(Thread.currentThread().getId())、線程名(Thread.currentThread().getName())、線程狀態(Thread.currentThread().getState())等

2、操作同一變量,但是線程調用run方法內容不同時,使用Thread內部類的方式進行,例如生產者、消費者模式

生產者消費者多線程例子:

 1 package com.loan.entity;
 2  
 3 public class Store {
 4     private final int MAX_SIZE=2;//倉庫總共可存放貨物
 5     private int count=0;//當前倉庫貨物
 6     public synchronized void add() throws InterruptedException{
 7         while(count>=MAX_SIZE){
 8             System.out.println("倉庫已滿");
 9             System.out.println(Thread.currentThread().getName()+"等待中。。。。");
10             this.wait();
11         }
12             count++;
13             System.out.println(Thread.currentThread().getName()+"存入倉庫,當前貨物數:"+count);
14             this.notify();
15     }
16     public synchronized void remove() throws InterruptedException{
17         while(count<=0){
18             System.out.println("倉庫空了");
19             System.out.println(Thread.currentThread().getName()+"等待中。。。。");
20             this.wait();
21         }
22             count--;
23             System.out.println(Thread.currentThread().getName()+"取出貨物,當前貨物數:"+count);
24             this.notify();
25     }
26     public static void main(String[] args) {
27         Store s=new Store();
28         Thread producer1=s.new Producer(s);//成員內部類需通過對象訪問
29         Thread producer2=s.new Producer(s);
30         Thread consumer1=s.new Consumer(s);
31         Thread consumer2=s.new Consumer(s);
32         producer1.setName("producer1");//利用Thread中的方法
33         producer2.setName("producer2");
34         consumer1.setName("consumer1");
35         consumer2.setName("consumer2");
36         producer1.start();
37         producer2.start();
38         consumer1.start();
39         consumer2.start();
40     }
41     class Producer extends Thread{
42         private Store store;
43         Producer(Store s){
44             store=s;
45         }
46         public void run(){
47             while(true){
48                 try {
49                     store.add();
50                     Thread.sleep(10000);
51                 } catch (InterruptedException e) {
52                     // TODO Auto-generated catch block
53                     e.printStackTrace();
54                 }
55             }
56         }
57     }
58     class Consumer extends Thread{
59         private Store store;
60         Consumer(Store s){
61             store=s;
62         }
63         public void run(){
64             while(true){
65                 try {
66                     store.remove();
67                     Thread.sleep(15000);
68                 } catch (InterruptedException e) {
69                     // TODO Auto-generated catch block
70                     e.printStackTrace();
71                 }
72             }
73         }
74     }
75 }

 

運行結果:

 

 

 

 

 

 

   


免責聲明!

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



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