Java从入门到精通 第22章 多线程
Java從入門到精通 第22章 多線程
//單一線程的運行流程 public class Nanjing {public static void main(String[] args) {// TODO, add your application codeSystem.out.println("Hello World!");//new TestThread.run();書上這樣寫的,會報錯,找不到符號TestThread tt=new TestThread();tt.run();new TestThread().run();//這種寫法也是可以的for(int i=0;i<5;i++)System.out.println("main is runing");} }class TestThread{public void run(){for(int i=0;i<5;i++)System.out.println("TestThread is Running...");} }Hello World!
TestThread is Running…
TestThread is Running…
TestThread is Running…
TestThread is Running…
TestThread is Running…
main is runing
main is runing
main is runing
main is runing
main is runing
22.2.1 通過繼承Thread類實現多線程
//同時激活多個線程 public class Nanjing {public static void main(String[] args) {// TODO, add your application codeSystem.out.println("Hello World!");new TestThread().start();//隱式的創建是可以的for(int i=0;i<5;i++){System.out.println("main is runing");try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}}} }class TestThread extends Thread{public void run(){for(int i=0;i<5;i++){System.out.println("TestThread is Running...");try{Thread.sleep(1000);}catch(InterruptedException ex){ex.printStackTrace();}}} }Hello World!
main is runing
TestThread is Running…
main is runing
TestThread is Running…
main is runing
TestThread is Running…
main is runing
TestThread is Running…
main is runing
TestThread is Running…
22.2.2 通過繼承Runnable接口實現多線程
public class Nanjing {public static void main(String[] args) {// TODO, add your application codeSystem.out.println("Hello World!");TestThread t=new TestThread();new Thread(t).start();for(int i=0;i<5;i++){System.out.println("main is runing");try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}}} }class TestThread implements Runnable{public void run(){for(int i=0;i<5;i++){System.out.println("TestThread is Running...");try{Thread.sleep(1000);}catch(InterruptedException ex){ex.printStackTrace();}}} }Hello World!
main is runing
TestThread is Running…
TestThread is Running…
main is runing
main is runing
TestThread is Running…
main is runing
TestThread is Running…
TestThread is Running…
main is runing
22.2.3 兩種多線程實現機制的比較
本質上,Thread類是Runnable接口的一個子類
public class Nanjing {public static void main(String[] args) {TestThread t=new TestThread();t.start();t.start();//一個線程只能啟動一次} }class TestThread extends Thread{private int ticketes=5;public void run(){while(ticketes>0){System.out.println(Thread.currentThread().getName()+" Saling ticket"+ticketes);ticketes-=1;}} }Thread-0 Saling ticket5
Thread-0 Saling ticket4
Thread-0 Saling ticket3
Thread-0 Saling ticket2
Thread-0 Saling ticket1
Exception in thread “main” java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:571)
at Test.main(Test.java:7)
Thread-1 Saling ticket5
Thread-1 Saling ticket4
Thread-1 Saling ticket3
Thread-1 Saling ticket2
Thread-1 Saling ticket1
Thread-0 Saling ticket5
Thread-0 Saling ticket4
Thread-0 Saling ticket3
Thread-0 Saling ticket2
Thread-0 Saling ticket1
Thread-2 Saling ticket5
Thread-2 Saling ticket4
Thread-2 Saling ticket3
Thread-2 Saling ticket2
Thread-2 Saling ticket1
//實際上Thread很難達到資源共享的目的,但是可以通過靜態變量達到資源共享
//Runnble相對于Thread有優勢
①避免Java單繼承帶來的局限
②可以使多個線程共享相同的資源,以達到資源共享之目的
//result
Thread-0 Saling ticket5
Thread-0 Saling ticket4
Thread-0 Saling ticket3
Thread-0 Saling ticket2
Thread-0 Saling ticket1
22.3 線程的狀態
//演示線程的生命周期 import java.util.Scanner; public class Nanjing {public static void main(String[] args) {Thread t=new Thread(new TestThread());System.out.println("Thead is at build state");t.start();System.out.println("Ready state");} }class TestThread implements Runnable{private int ticketes=5;public void run(){System.out.println("Runing...");Scanner scanner=new Scanner(System.in);System.out.println("Waiting I/O,Blocking");System.out.println("Please input String:");scanner.next();scanner.close();System.out.println("Block over,Re-enter the ready state and then enter the running state");try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}System.out.println("Thread enter dead state");} }//result
Thead is at build state
Ready state
Runing…
Waiting I/O,Blocking
Please input String:
Naning science and technology institute//輸入完后停頓了1秒
Block over,Re-enter the ready state and then enter the running state
Thread enter dead state
22.4 線程操作的一些方法
22.4.1取得和設置線程名稱
//線程名稱的操作 public class Nanjing {public static void main(String[] args) {TestThread t=new TestThread();t.start();for(int i=0;i<3;i++){t.printMsg();try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}}} }class TestThread extends Thread{public void run(){for(int i=0;i<3;i++){printMsg();try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}}}public void printMsg(){Thread t=Thread.currentThread();//獲得運行此代碼的線程的引用String name=t.getName();System.out.println("name="+name);} }//result
name=main
name=Thread-0
name=main
name=Thread-0
name=main
name=Thread-0
22.4.3守護線程與setDaemon方法
ThreadTest t=new ThreadTest(); Treat tt=newThread(t); tt.setDaemon(true);//設置守護線程,一定要在start()之前 tt.start(); //主線程main結束就隨之終止了 //當java虛擬機中沒有非守護線程在運行的時候,java虛擬機會關閉。當所有常規線程運行完畢以后,守護線程不管運行到哪里,虛擬機都會退出運行。所以你的守護線程最好不要寫一些會影響程序的業務邏輯。否則無法預料程序到底 會出現什么問題。22.4.4 線程的聯合
//演示線程的強制執行 ThreadTest t=new ThreadTest(t); pp.start(); int i=0; for(int x=0;x<5;x++) if(i==3) try{ pp.join();//強制運行完pp線程后,再運行后面的進程,使主線程暫時掛起 }22.4.5 線程的中斷
//線程中斷的使用范例 public class Nanjing {public static void main(String[] args) {TestThread tt=new TestThread();Thread t=new Thread(tt);t.start();try{Thread.sleep(2000);}catch(InterruptedException e){e.printStackTrace();}System.out.println("at main()method,interrupt other thread");t.interrupt();System.out.println("at main()method,exit");} }class TestThread implements Runnable{public void run(){try{System.out.println("at run() method,let this thread sleep 10 seconds");Thread.sleep(10000);System.out.println("at run() method,continue runing");}catch(InterruptedException x){System.out.println("at run() method,interrupt thread");return;}System.out.println("at run() method,continue to complete after sleep");System.out.println("at run() method,normally exit");} }//result
at run() method,let this thread sleep 10 seconds
at main()method,interrupt other thread
at run() method,interrupt thread
at main()method,exit
22.5多線程的同步
同步代碼塊
synchronized{
}
//result
Thread-0saling ticket5
Thread-1saling ticket4
Thread-2saling ticket3
Thread-1saling ticket2
Thread-0saling ticket1
Thread-1saling ticket0
同步方法
public sychoronized void sale(){}
Thread-0 saling ticket5
Thread-2 saling ticket4
Thread-1 saling ticket3
Thread-0 saling ticket2
Thread-2 saling ticket1
22.5.4死鎖
如果一組進程,其中的每個都無限等待該組進程中的另一個進程所占據的資源,就會產生無限期的僵持下去的局面,這種現象就是死鎖
Java多線程中,最常見的死鎖形式是當線程1已經占據資源R1,并持有資源R1上的鎖,而正在等待資源2開鎖;而線程2已經占據資源R2,并且持有R2上的鎖,正在等待資源R1開鎖。如果倆個線程不釋放自己占據的資源鎖,而還申請對方資源上的鎖,申請不到時就等待,那么他們只能永遠等待下去
//模擬死鎖的發生 public class DeadLock{static String knife="knife",fork="fork";static class A extends Thread{public void run(){synchronized(knife){System.out.println("A take "+knife+", waiting "+fork+"...");try{Thread.sleep(100);}catch(InterruptedException e){}synchronized(fork){//由于死鎖的原因,這里永遠不會執行System.out.println("A take "+fork);}}}}static class B extends Thread{public void run(){synchronized(fork){System.out.println("B take "+fork+", waiting for "+knife+"...");try{Thread.sleep(1000);}catch(InterruptedException e){}synchronized(knife){System.out.println("B take knife");} }}}static class Demo extends Thread{public Demo(){this.setDaemon(true);}public void run(){while(true){try{Thread.sleep(1000);}catch(InterruptedException e){}System.out.println("protected thread:program is running...");}}}public static void main(String[] args){new A().start();new B().start();new Demo().start();} }//result
A take knife, waiting fork…
B take fork, waiting for knife…
protected thread:program is running…
protected thread:program is running…
protected thread:program is running…
protected thread:program is running…
22.6線程間的通信
22.6.1問題的引出
一個線程向數據存儲空間中添加數據(生產者),另一個線程從數據空間中取出數據(消費者)。這個程序有兩種以外需要考慮。
第一種以外,假設生產者線程剛向數據存儲空間中添加了一個人的姓名,還沒有加入這個人的性別,CPU就切換到了消費者線程,消費者線程則把這個人的姓名和上一個人的性別聯系到了一起
第二種意外,生產者放入了若干數據,消費者才開始讀取數據,或者是消費者讀取完一個數據后,還沒等到生產者放入新的數據,又重新取出已經取過的數據。
在操作系統里,上面的案例屬于經典的同步問題——生產者消費者問題
可以過線程間的通信來解決以上問題
//result
ZhangSan—>female
ZhangSan—>female
LiSi—>male
ZhangSan—>female
ZhangSan—>female
LiSi—>male
LiSi—>male
ZhangSan—>female
LiSi—>male
ZhangSan—>female
//result
LiSi—>male
LiSi—>male
LiSi—>male
LiSi—>male
LiSi—>male
LiSi—>male
LiSi—>male
LiSi—>male
LiSi—>male
LiSi—>male
//example analysis
雖然保證了李四是女的,但是又產生了另外的問題,Consumer線程對Producer線程放入的數據連續的讀取多次,多次輸出:Lisi—>male這并不符合實際要求。合理的結果是Producer放入一次數據,Consumer就取一次;反之。Producer必須等到Consumer取完后才能放入新的數據,而這一問題就需要線程通信
Java通過Object類的wait() noify() notifyAll()這幾個發方法來實現線程通信
wait() 通知當前線程進入睡眠狀態
notify()喚醒在該同步代碼塊中第一個調用的wait()的線程
ntifyAll()喚醒該同步代碼塊中所有調用wait()的線程,具有高優先級的線程首先被喚醒并執行
//result
ZhangSan—>male
LiSi—>female
ZhangSan—>male
LiSi—>female
ZhangSan—>male
LiSi—>female
ZhangSan—>male
LiSi—>female
ZhangSan—>male
LiSi—>female
22.8總結
1.線程的幾個特點
(1)同步代碼塊和同步方法鎖的是對象,而不是代碼。即如果某個對象被同步代碼塊或同步方法鎖住,那么其他使用該對象的代碼必須等待,直到該對象的鎖被釋放
(2)如果一個進程只有后臺進程,則這個進程就會結束
(3)每個已經被創建的線程在結束之前均會處于就緒、運行、阻塞狀態之一
2.另外一種多線程同步的鎖機制
java.util.concurrent.locks
3.Java 8新引入Lambda表達式
總結
以上是生活随笔為你收集整理的Java从入门到精通 第22章 多线程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高考 填志愿 查学校历年录取分数线
- 下一篇: Highway (树的直径 + dfs