<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
建立子類,繼承自Thread並且重寫run方法:
class MyThread extends Thread { @Override public void run() { System.out.println("hello thread"); } } public class Demo1 { public static void main(String[] args) { // 最基本的建立執行緒的辦法. Thread t = new MyThread(); //呼叫了start方法才是真正的在系統中建立了執行緒,執行run方法 t.start(); } }
建立一個類,實現Runnable介面再建立Runnable是範例傳給Thread
class MyRunnable implements Runnable{ @Override public void run() { System.out.println("hello"); } } public class Demo3 { public static void main(String[] args) { Thread t = new Thread(new MyRunnable()); t.start(); } }
匿名內部類:
建立了一個匿名內部類,繼承自Thread類,同時重寫run方法,再new出匿名內部類的範例
public class Demo4 { public static void main(String[] args) { Thread t = new Thread(){ @Override public void run() { System.out.println("hello"); } }; t.start(); } }
new的Runnable,針對這個建立的匿名內部類,同時new出的Runnable範例傳給Thread的構造方法
public class Demo5 { public static void main(String[] args) { Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("hello"); } }); t.start(); } }
lambda表示式 lambda代替Runnable
public class Demo6 { public static void main(String[] args) { Thread t = new Thread(() ->{ System.out.println("hello"); }); t.start(); } }
run和start的區別:run單純的只是一個普通方法描述了任務的內容 start則是一個特殊的方法,內部會在系統中建立執行緒
執行緒停下來的關鍵是要讓對應run方法執行完,對於main執行緒來說main方法執行完了才會終止
線上程中控制這個標誌位就能影響到這個執行緒結束,但是此處多個執行緒共用一片虛擬空間,因此main執行緒修改的isQuit和t執行緒判斷的isQuit是同一個值
public class Demo10 { // 通過這個變數來控制執行緒是否結束. private static boolean isQuit = false; public static void main(String[] args) { Thread t = new Thread(() -> { while (!isQuit) { System.out.println("hello thread"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }); t.start(); // 就可以在 main 執行緒中通過修改 isQuit 的值, 來影響到執行緒是否退出 try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } // main 執行緒在 5s 之後, 修改 isQuit 的狀態. isQuit = true; } }
Thread.interruted()這是一個靜態方法 Thread.currentThread().isInterrupted()這是一個實體方法,其中currentThread能夠獲取到當前執行緒的範例
public class Demo7 { public static void main(String[] args) { Thread t = new Thread(() -> { while(!Thread.currentThread().isInterrupted()){ System.out.println("hello"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); // 當觸發異常之後, 立即就退出迴圈~ System.out.println("這是收尾工作"); break; } } }); t.start(); try{ Thread.sleep(5000); }catch (InterruptedException e){ e.printStackTrace(); } // 在主執行緒中, 呼叫 interrupt 方法, 來中斷這個執行緒. // t.interrupt 的意思就是讓 t 執行緒被中斷!! t.interrupt(); } }
需要注意的是呼叫這個方法t.interrupt()可能會產生兩種情況:
多個執行緒之間排程順序是不確定的,有時候我們需要控制執行緒之間的順序,執行緒等待就是一種控制執行緒執行順序的手段,此處的執行緒等待只要是控制執行緒結束的先後順序。
哪個執行緒中的join,哪個執行緒就會阻塞等待直到對應的執行緒執行完畢為止。
Thread.currentThread()
能夠獲取當前執行緒的應用,哪個執行緒呼叫的currentThread就獲取到哪個執行緒的範例 對比this如下:
對於這個程式碼來說,通過繼承Thread的方法來建立執行緒。此時run方法中直接通過this拿到的就是當前Thread的範例
public class Demo4 { public static void main(String[] args) { Thread t = new Thread(){ @Override public void run() { System.out.println(Thread.currentThread().getName()); System.out.println(this.getName()); } }; t.start(); } }
然而此處this不是指向Thread型別,而是指向Runnable,Runnable只是一個單純的任務沒有name屬性,要想拿到執行緒名字只能通過Thread.currentThread()
public class Demo5 { public static void main(String[] args) { Thread t = new Thread(new Runnable() { @Override public void run() { //err //System.out.println(this.getName()); //right System.out.println(Thread.currentThread().getName()); } }); t.start(); } }
針對系統層面:
java中Thread類進一步細化:
狀態轉換圖:
定義:作業系統中執行緒排程是隨機的,導致程式的執行可能會出現一些bug。如果因為排程隨機性引入了bug執行緒就是不安全的,反之則是安全的。
解決方法:加鎖,給方法直接加上synchronized關鍵字,此時進入方法就會自動加鎖,離開方法就會自動解鎖。當一個執行緒加鎖成功的時候,其他執行緒嘗試加鎖就會觸發阻塞等待,阻塞會一直持續到佔用鎖的執行緒把鎖釋放為止。
synchronized public void increase() { count++; }
執行緒不安全產生的原因:
記憶體可見性解決方法:
在java中每個類都是繼承自Object,每個new出來的範例裡面一方面包含自己安排的屬性,另一方面包含了“物件頭”即物件的一些後設資料。加鎖操作就是在這個物件頭裡面設定一個標誌位。
使用synchronized的時候本質上是對某個“物件”進行加鎖,此時的鎖物件就是this。加鎖操作就是在設定this的物件頭的標誌位,當兩個執行緒同時嘗試對同一個物件加鎖的時候才有競爭,如果是兩個執行緒在針對兩個不同物件加鎖就沒有競爭。
class Counter{ public int count; synchronized public void increase(){ count++; } }
需要顯示制定針對那個物件加鎖(java中的任意物件都可以作為鎖物件)
public void increase(){ synchronized(this){ count++; } }
相當於針對當前類的類物件加鎖,類物件就是執行程式的時候。class檔案被載入到JVM記憶體中的模樣。
synchronized public static void func(){ }
或者
public static void func(){ synchronized(Counter.class){ } }
可重入鎖就是同一個執行緒針對同一個鎖,連續加鎖兩次,如果出現死鎖就是不可重入鎖,如果不會死鎖就是可重入的。因此就把synchronized實現為可重入鎖,下面的例子裡啊連續加鎖操作不會導致死鎖。可重入鎖內部會記錄所被哪個執行緒佔用也會記錄加鎖次數,因此後續再加鎖就不是真的加鎖而是單純地把技術給自增。
synchronized public void increase(){ synchronized(this){ count++; } }
死鎖的四個必要條件(前三個都是鎖本身的特點)
java執行緒類:
禁止編譯器優化保證記憶體可見性,產生原因:計算機想執行一些計算就需要把記憶體的資料讀到CPU暫存器中,然後再從暫存器中計算寫回到記憶體中,因為CPU存取暫存器的速度比存取記憶體快很多,當CPU連續多次存取記憶體結果都一樣,CPU就會選擇存取暫存器。
JMM(Java Memory Model)Java記憶體模型
就是把硬體結構在java中用專業的術語又重新抽象封裝了一遍。
暫存器,快取和記憶體之間的關係
CPU從記憶體取資料太慢,因此把資料直接放到暫存器裡來讀,但暫存器空間太緊張於是又搞了一個儲存空間,比暫存器大比記憶體小速度比暫存器慢比記憶體快稱為快取。暫存器和快取統稱為工作記憶體。
暫存器,快取和記憶體之間的關係圖
volatile和synchronized的區別
wait和notify
等待和通知處理執行緒排程隨機性問題的,join也是一種控制順序的方式更傾向於控制執行緒結束。wait和notify都是Object物件的方法,呼叫wait方法的執行緒就會陷入阻塞,阻塞到有執行緒通過notify來通知。
public class Demo9 { public static void main(String[] args) throws InterruptedException { Object object = new Object(); System.out.println("wait前"); object.wait(); System.out.println("wait後"); } }
wait內部會做三件事;
因此想用wait/notify就得搭配synchronized
public class Demo9 { public static void main(String[] args) throws InterruptedException { Object object = new Object(); synchronized (object){ System.out.println("wait前"); object.wait(); System.out.println("wait後"); } } }
注意:wait notify都是針對同一物件來操作的,例如現在有一個物件o,有10個執行緒都呼叫了o.wait,此時10個執行緒都是阻塞狀態。如果呼叫了o.notify就會把10個執行緒中的一個執行緒喚醒。而notifyAll就會把所有10個執行緒全都給喚醒,此時就會競爭鎖。
到此這篇關於Java多執行緒Thread類的使用及注意事項的文章就介紹到這了,更多相關Java Thread 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45