一、概念
Thread實現了Runnable接口
1 public class Thread implements Runnable { 2 /* Make sure registerNatives is the first thing <clinit> does. */ 3 private static native void registerNatives(); 4 static { 5 registerNatives(); 6 } 7 8 private volatile char name[]; 9 //表示線程的優先級(最大值為10,最小值為1,默認值為5), 10 private int priority; 11 12 13 /* Whether or not the thread is a daemon thread. */ 14 //表示線程是否是守護線程,如果在main線程中創建了一個守護線程, 15 //當main方法運行完畢之后,守護線程也會隨着消亡。在JVM中,垃圾收集器線程就是守護線程。 16 private boolean daemon = false; 17 18 19 /* What will be run. */ 20 //表示要執行的任務。 21 private Runnable target; 22 。。。。。。 23 }
二、創建,啟動線程的方法有兩種:
1,繼承Thread
1 class PrimeThread extends Thread { 2 long minPrime; 3 PrimeThread(long minPrime) { 4 this.minPrime = minPrime; 5 } 6 7 public void run() { 8 // compute primes larger than minPrime 9 . . . 10 } 11 } 12 13 PrimeThread p = new PrimeThread(143); 14 p.start();
2,實現Runnable
1 class PrimeRun implements Runnable { 2 long minPrime; 3 PrimeRun(long minPrime) { 4 this.minPrime = minPrime; 5 } 6 7 public void run() { 8 // compute primes larger than minPrime 9 . . . 10 } 11 } 12 13 14 PrimeRun p = new PrimeRun(143); 15 new Thread(p).start();
3,分析
但都調用thread的start()啟動線程,API的注解是:
Causes this thread to begin execution; the Java Virtual Machine calls the <code>run</code> method of this thread.(使該線程開始執行;Java 虛擬機調用該線程的 run 方法。)
用start方法來啟動線程,真正實現了多線程運行,這時無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼。通過調用Thread類的start()方法來啟動一個線程,這時此線程處於就緒(可運行)狀態,並沒有運行,一旦得到cpu時間片,就開始執行run()方法,這里方法 run()稱為線程體,它包含了要執行的這個線程的內容,Run方法運行結束,此線程隨即終止。
而thread的run()方法只是一個普通方法而已,API的注解是:
If this thread was constructed using a separate <code>Runnable</code> run object, then that <code>Runnable</code> object's <code>run</code> method is called;otherwise, this method does nothing and returns.(如果該線程是使用獨立的 Runnable
運行對象構造的,則調用該 Runnable
對象的 run
方法;否則,該方法不執行任何操作並返回。)
如果直接調用Run方法,程序中依然只有主線程這一個線程,其程序執行路徑還是只有一條,還是要順序執行,還是要等待run方法體執行完畢后才可繼續執行下面的代碼,這樣就沒有達到寫線程的目的。
1 public class ThreadTest extends Thread{ 2 3 @Override 4 public void run() { 5 System.out.println("Thread Start !"); 6 } 7 8 public static void main(String[] args) { 9 ThreadTest threadTest = new ThreadTest(); 10 threadTest.start(); 11 System.out.println("不用等待!"); 12 } 13 }
結果:
1 不用等待! 2 Thread Start !
1 public class ThreadTest extends Thread{ 2 3 @Override 4 public void run() { 5 System.out.println("Thread Start !"); 6 } 7 8 public static void main(String[] args) { 9 ThreadTest threadTest = new ThreadTest(); 10 threadTest.run(); 11 System.out.println("不用等待!"); 12 } 13 }
結果:
1 Thread Start ! 2 不用等待!
參考博文鏈接: https://www.cnblogs.com/renhui/p/6066750.html
三、關於賣票的問題:
1,extends Thread
1 public class MyThread extends Thread { 2 private int tickets = 10; 3 @Override 4 public void run() { 5 6 for (int i = 0; i <= 100; i++) { 7 if(tickets>0){ 8 System.out.println(Thread.currentThread().getName()+"--賣出票:" + tickets--); 9 } 10 } 11 } 12 public static void main(String[] args) { 13 MyThread thread1 = new MyThread(); 14 MyThread thread2 = new MyThread(); 15 MyThread thread3 = new MyThread(); 16 17 thread1.start(); 18 thread2.start(); 19 thread3.start(); 20 } 21 }
結果:
1 Thread-0--賣出票:10 2 Thread-2--賣出票:10 3 Thread-2--賣出票:9 4 Thread-2--賣出票:8 5 Thread-2--賣出票:7 6 Thread-2--賣出票:6 7 Thread-1--賣出票:10 8 Thread-1--賣出票:9 9 Thread-2--賣出票:5 10 Thread-0--賣出票:9 11 Thread-0--賣出票:8 12 Thread-0--賣出票:7 13 Thread-0--賣出票:6 14 Thread-0--賣出票:5 15 Thread-0--賣出票:4 16 Thread-0--賣出票:3 17 Thread-0--賣出票:2 18 Thread-0--賣出票:1 19 Thread-2--賣出票:4 20 Thread-1--賣出票:8 21 Thread-2--賣出票:3 22 Thread-1--賣出票:7 23 Thread-2--賣出票:2 24 Thread-1--賣出票:6 25 Thread-2--賣出票:1 26 Thread-1--賣出票:5 27 Thread-1--賣出票:4 28 Thread-1--賣出票:3 29 Thread-1--賣出票:2 30 Thread-1--賣出票:1
問題:每個線程都獨立,不共享資源,每個線程都賣出了10張票,總共賣出了30張。
2,implements Runnable
1 public class MyRunnable implements Runnable { 2 3 private int tickets = 64100; 4 @Override 5 public void run() { 6 for (int i = 0; i <= 64200; i++) { 7 if(tickets>0){ 8 System.out.println(Thread.currentThread().getName()+"--賣出票:"+ tickets-- ); 9 } 10 } 11 } 12 13 public static void main(String[] args) { 14 MyRunnable myRunnable = new MyRunnable(); 15 Thread thread1 = new Thread(myRunnable, "窗口一"); 16 Thread thread2 = new Thread(myRunnable, "窗口二"); 17 Thread thread3 = new Thread(myRunnable, "窗口三"); 18 19 thread1.start(); 20 thread2.start(); 21 thread3.start(); 22 } 23 }
問題:每個線程共享了對象myRunnable的資源,但是當tickets足夠大的時候就會出現一張票被賣出去多次的問題,原因是:讀取共享變量tickets和減一這兩個動作是原子操作,但這兩個動作不可能用一條指令完成,一旦在這兩個動作之間發生線程的切換,同一個值就會被讀取2次,從而發生錯誤!
解決方案就是在方法上加鎖:
1 synchronized (this) { 2 if (tickets > 0) { 3 System.out.println(Thread.currentThread().getName() + "--賣出票:" + tickets--); 4 } 5 }
四、拓展
關於Thread的詳細源碼剖析可參考:https://www.cnblogs.com/dennyzhangdd/p/7280032.html
關於Thread多次start一個線程報錯:IllegalThreadStateException()
----------------------------------------------多做多解決多總結-----------------------------------