線程概念
一:程序 進程 線程
- 程序:Program 編寫的代碼,指令集,靜態概念
- 進程:Process 操作系統調度程序,動態概念 作爲資源分配的單位
- 線程:Thread 進程內多條執行路徑 輕量級進程 調度和執行的單位 線程使用的資源是它所屬進程的資源 只能共享資源 除CPU外不會爲線程分配內存
線程創建
一:繼承Thread + 重寫run()方法Rabbit.javapublic class Rabbit extends Thread { public void run() { for(int i=0; i<5; i++) { System.out.println("Rabbit: " + i); } } }
啓動:創建子類對象 + 調用子類對象.start()方法RabbitApp.javapublic class RabbitApp { public static void main(String[] args) { Rabbit rabbit = new Rabbit(); //Tortoise tortoise = new Tortoise(); rabbit.start(); //tortoise.start(); } }
二:實現Runnable接口 + 重寫run()方法Programmer.javapublic class Programmer implements Runnable { @Override public void run() { for(int i=0; i<5; i++) { System.out.println("Programmer: " + i); } } }
啓動:創建真實角色
創建代理角色:Thread + 對真實角色的引用代理角色.start()
ProgrammerApp.java
public class ProgrammerApp { public static void main(String[] args) { Programmer programmer = new Programmer(); Thread proxy = new Thread(programmer); proxy.start(); //for(int i=0; i<5; i++) { // System.out.println("main: " + i); //} } }
推薦:使用接口
- 避免單繼承侷限性
- 便於共享資源
三:創建Callable實現類 + 重寫call()方法 可以拋檢查時異常 前面的run()方法是不能拋異常的
線程狀態
一:線程狀態轉換圖新生狀態:用new關鍵字和Thread類或其子類建立一個線程對象後,該線程對象就處於新生狀態。處於新生狀態的線程有自己的內存空間,通過調用start方法進入就緒狀態(runnable)就緒狀態:處於就緒狀態的線程已經具備了運行條件,但還沒有分配到CPU,處於線程就緒隊列,等待系統爲其分配CPU。等待狀態並不是執行狀態,當系統選定一個等待執行的Thread對象後,它就會從等待執行狀態進入執行狀態,系統挑選的動作稱之爲”CPU調度“。一旦獲得CPU,線程就進入運行狀態並自動調用自己的run方法。運行狀態:在運行狀態的線程執行自己的run方法中,代碼直到調用其他方法而終止,或等待某資源而阻塞或完成任務而死亡。如果過在給定的時間片內沒有執行結束,就會被系統給換下來回到等待執行狀態。運行狀態:處於就緒狀態的線程獲得CPU時間片後,進入運行狀態,真正開始執行run方法。阻塞狀態:處於運行狀態的線程在某些情況下,如執行了sleep(睡眠)方法,或等待I/O設備等資源,將讓出CPU並暫時停止自己的運行,進入阻塞狀態。在阻塞狀態的線程不能進入就緒隊列。只有當引起阻塞的原因消除時,如睡眠時間已到,或等待的I/O設備空閒下來,線程便轉入就緒狀態,重新到就緒隊列中排隊等待,被系統選中後從原來停止的位置開始繼續執行。死亡狀態:死亡狀態是線程生命週期中的最後一個階段。線程死亡的原因有兩個。一個是正常運行的線程完成了它的全部工作;另一個是線程被強制性的終止,如通過執行stop或destroy方法來終止一個線程【不推薦使用這兩個方法。前者會產生異常,後者是強制終止,不會釋放鎖。】
停止線程
一:自然終止 線程體自然執行完畢二:外部干涉
- 線程體中定義線程體使用的標識
- 線程體使用該標識
- 提供對外的方法改變該標識
- 外部根據條件調用該方法即可
StopDemo01.javapublic class StopDemo01 { public static void main(String[] args) { Study study = new Study(); Thread thread = new Thread(study); thread.start(); for(int i=0; i<100; i++) { if(i==50) { study.stop(); } System.out.println("main thread->" + i); } } } class Study implements Runnable { private boolean flag = true; public void run() { while(flag) { System.out.println("study thread..."); } } public void stop() { this.flag = false; } }
線程阻塞
一:join 合併線程JoinDemo01.java二:yield 暫停自己的線程 staticpublic class JoinDemo01 extends Thread { public static void main(String[] args) throws Exception { JoinDemo01 joindemo01 = new JoinDemo01(); Thread t = new Thread(joindemo01); t.start(); for(int i=0; i<100; i++) { if(i==50) { t.join(); //main阻塞 } System.out.println("main thread..." + i); } } public void run() { for(int i=0; i<100; i++) { System.out.println("join thread..." + i); } } }<strong> </strong>
YeildDemo01.java三:sleep 休眠,不釋放鎖 staticpublic class YieldDemo01 extends Thread { public static void main(String[] args) { JoinDemo01 joindemo01 = new JoinDemo01(); Thread t = new Thread(joindemo01); t.start(); for(int i=0; i<100; i++) { if(i%10==0) { Thread.yield(); //暫停本線程main } System.out.println("main thread..." + i); } } public void run() { for(int i=0; i<100; i++) { System.out.println("yield thread..." + i); } } }
- 與時間相關:倒計時
- 模擬網絡延時
SleepDemo01.javapublic class SleepDemo01 { public static void main(String[] args) throws Exception { int num = 10; while(num>=0) { Thread.sleep(1000); System.out.println(num); num--; } } }
線程基本信息
Thread.currentThread() //當前線程 staticsetName() //設置名稱getName() //獲取名稱isAlive() //判斷狀態優先級:概率大小,不是絕對的先後順序setPriority() //設置優先級大小getPriority() //獲取優先級MyThready.java
InfoDemo01.javapublic class MyThread implements Runnable { private boolean flag = true; private int num = 0; public void run() { while(flag) { System.out.println(Thread.currentThread().getName() + "->" + num); num++; } } public void stop() { this.flag = !this.flag; } }
InfoDemo02.javapublic class InfoDemo01 { public static void main(String[] args) throws Exception { MyThread mythread = new MyThread(); Thread proxy = new Thread(mythread); proxy.setName("test"); System.out.println(proxy.getName()); System.out.println(Thread.currentThread().getName()); proxy.start(); Thread.sleep(100); mythread.stop(); } }
package com.cho3en1.thread.info; public class InfoDemo02 { public static void main(String[] args) throws Exception { MyThread mythread1 = new MyThread(); MyThread mythread2 = new MyThread(); Thread t1 = new Thread(mythread1); Thread t2 = new Thread(mythread2); t1.setPriority(Thread.MAX_PRIORITY); t2.setPriority(Thread.MIN_PRIORITY); t1.start(); t2.start(); Thread.sleep(200); mythread1.stop(); mythread2.stop(); } <h2>}</h2>
線程同步與鎖定
同步:併發 多個線程訪問同一份資源 確保資源安全synchronized -> 同步一:同步塊synchronized(引用類型|this|類.class) {}二:同步方法synchronizedSynDemo01.javapublic class SynDemo01 { public static void main(String[] args) { Web12306 w = new Web12306(); Thread p1 = new Thread(w, "黃牛1"); Thread p2 = new Thread(w, "黃牛2"); Thread p3 = new Thread(w, "黃牛3"); p1.start(); p2.start(); p3.start(); } } class Web12306 implements Runnable { private boolean flag = true; private int num = 50; @Override public void run() { while(flag) { test1(); } } public synchronized void test1() { if(num<=0) { flag = false; return; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "搶到了" + num--); } }
三:死鎖SynDemo02.javapublic class SynDemo02 { public static void main(String[] args) { Test t1 = new Test(); Test t2 = new Test(); t1.flag = true; t2.flag = false; Thread proxy1 = new Thread(t1); Thread proxy2 = new Thread(t2); proxy1.start(); proxy2.start(); } } class Test implements Runnable { public boolean flag; static Object goods = new Object(); static Object money = new Object(); public void run() { while(true) { test(); } } public void test() { if(flag == true) { synchronized (goods) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (money) { System.out.println("一手給錢"); } } } if(flag == false) { synchronized (money) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (goods) { System.out.println("一手給貨"); } } } } }