- 讓類成爲線程類有兩種方式,實現Runnable接口,以及繼承Thread類(類中實現了Runnable接口,還提供了一些額外的方法)。 java
1、Runnable相對優點:
-
java的單繼承,當繼承了Thread類,則不能繼承其餘類,而實現Runnable接口能夠
-
實現Runnable接口的線程類的多個線程,能夠訪問同一變量,而Thread則不能(多窗口買票問題)
緣由:兩種方式啓動方式不一樣:多線程
- Runnable線程類是實例化一個對象o以後,經過屢次new Thread(o).start();啓動多個線程,而這幾個線程屬於一個對象,對象的成員變量是同一個。
- Thread線程類啓動多個線程須要 new MyThread().start();每一個線程啓動都對應多個對象,他們的成員變量是獨立的。
測試代碼以下:ide
(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 }
運行結果:
2、Thread優點
一、使用線程的方法方便一些,例如:獲取線程的Id(Thread.currentThread().getId())、線程名(Thread.currentThread().getName())、線程狀態(Thread.currentThread().getState())等
二、操做同一變量,可是線程調用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 }