實現多線程的方式:
實現多線程的方式有多種,這里只列舉兩種常用的,而第一種繼承Thread的方式無法實現多窗口賣票。
一,繼承Thread方式:
特點:多線程多實例,無法實現資源的共享。
例子:
1 package com.demo.study.multithreading; 2 3 public class MyThread extends Thread{ 4 5 private int i = 10; 6 // 可以自行定義鎖,也可以使用實例的鎖 7 Object mutex = new Object(); 8 public void selltickets(){ 9 10 synchronized (mutex) { 11 12 if(i>0){ 13 i--; 14 //getName()獲取線程的名字 15 System.out.println(Thread.currentThread().getName()+" :"+ i); 16 } 17 } 18 } 19 20 @Override 21 public void run() { 22 while(i>0){ 23 24 selltickets(); 25 } 26 } 27 }
啟動線程:
1 package com.demo.study.multithreading; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 //繼承Thread方式:多線程多實例,無法實現資源的共享 7 MyThread myThread1 = new MyThread(); 8 MyThread myThread2 = new MyThread(); 9 //給線程命名 10 myThread1.setName("線程1"); 11 myThread2.setName("線程2"); 12 myThread1.start(); 13 myThread2.start(); 14 } 15 }
運行結果:
二,實現Runnable方式:
特點:多線程單實例,可實現資源的共享
例子:實現多窗口賣票:
1 package com.demo.study.multithreading; 2 3 public class MyThreadImpl implements Runnable { 4 5 private int tickets = 10; 6 7 public void sellTickets() { 8 9 synchronized (MyThreadImpl.class) { 10 if (tickets > 0) { 11 12 tickets--; 13 System.out.println(Thread.currentThread().getName() + "正在賣票,還剩下" + tickets + "張"); 14 } 15 } 16 } 17 18 @Override 19 public void run() { 20 21 while (tickets > 0) { 22 sellTickets(); 23 try { 24 // 休眠一秒,讓執行的效果更明顯 25 Thread.sleep(100); 26 } catch (InterruptedException e) { 27 e.printStackTrace(); 28 } 29 } 30 } 31 }
啟動線程:
注意:Thread中的start()方法是線程的就緒,而線程的啟動,需要等待CPU的調度(也就是所謂的線程搶資源);run()方法的方法體代表了線程需要完成的任務,稱之為線程執行體。
void |
start() 使該線程開始執行;Java 虛擬機調用該線程的 run 方法。 |
1 package com.demo.study.multithreading; 2 3 public class Test { 4 5 public static void main(String[] args) { 6 7 //只創建一個實例 8 MyThreadImpl threadImpl = new MyThreadImpl(); 9 //將上面創建的唯一實例放入多個線程中,Thread類提供了多個構造方法,見下圖(構造方法摘要) 10 Thread thread1 = new Thread(threadImpl, "窗口1"); 11 Thread thread2 = new Thread(threadImpl, "窗口2"); 12 thread1.start(); 13 thread2.start(); 14 15 } 16 }
構造方法摘要 | |
---|---|
Thread() 分配新的 Thread 對象。 |
|
Thread(Runnable target) 分配新的 Thread 對象。 |
|
Thread(Runnable target, String name) 分配新的 Thread 對象。 |
|
Thread(String name) 分配新的 Thread 對象。 |
|
Thread(ThreadGroup group, Runnable target) 分配新的 Thread 對象。 |
|
Thread(ThreadGroup group, Runnable target, String name) 分配新的 Thread 對象,以便將 target 作為其運行對象,將指定的 name 作為其名稱,並作為 group 所引用的線程組的一員。 |
|
Thread(ThreadGroup group, Runnable target, String name, long stackSize) 分配新的 Thread 對象,以便將 target 作為其運行對象,將指定的 name 作為其名稱,作為 group 所引用的線程組的一員,並具有指定的堆棧大小。 |
|
Thread(ThreadGroup group, String name) 分配新的 Thread 對象。 |
運行結果:
三、同步鎖與資源共享:
CPU可能隨機的在多個處於就緒狀態中的線程中進行切換,這時就可能出現線程的安全問題;線程安全問題,其實是指多線程環境下對共享資源的訪問可能會引起此共享資源的不一致性,而解決安全問題則需要同步鎖的加入,執行synchronized部分代碼的時候必須需要對象鎖,而一個對象只有一個鎖,只有執行完synchronized里面的代碼后釋放鎖,其他線程才可以獲得鎖,那么就保證了同一時刻只有一個線程訪問synchronized里面的代碼。實現資源共享的關鍵是,只有一個實例,synchronized使用的是同一把鎖,用實例的鎖或者定義一個實例。這就需要使用實現Runnable接口的方式,實現多線程,這樣傳入的是一個實例。繼承Thread的方式,傳入的是多個實例,每個實例都有一個鎖,那就無法實現控制。