java多執行緒總結
看著秦疆老師的課一個一個跟著敲下來的, 最后總結出了一篇博客, 用于以后復習, 還有二級標題點進去是視頻課
這篇博文有些粗糙, 排版什么的有點亂…
還有, 如果發現有錯別字或者啥錯誤的, 麻煩跟我說一聲叭, 謝謝~
文章目錄
- java多執行緒總結
- @[toc]
- [03繼承Thread類]
- 三種創建方式
- Thread類
- [04網圖下載]
- 案例:下載圖片
- [05實作Runnable介面]
- Runnable介面
- 小結
- 繼承Thread類
- 實作runnable介面
- [06初識并發問題]
- 買票問題
- [07龜兔賽跑]
- 案例龜兔-race
- 代碼開始啦
- [08實作Callable介面]
- 了解即可
- [09靜態代理模式]
- 舉例
- 代碼實作
- 總結
- [10Lambda運算式]
- 簡單介紹lambda
- 函式式介面
- 代碼實作1
- 代碼實作2
- [11執行緒停止]
- 執行緒狀態
- 執行緒方法
- Stop
- [12休眠執行緒sleep]
- 代碼示例1
- 代碼示例2 倒計時
- 代碼示例3 時間表
- [13執行緒禮讓Yield]
- [14執行緒強制執行Join]
- [15觀測執行緒狀態]
- Thread.State
- [16執行緒的優先級]
- 內容
- 注意
- [17守護執行緒]
- deamon
- [18執行緒同步機制]
- [19三大不安全案例]
- 舉例,不安全的買票
- 舉例,不安全的取錢
- 舉例三
- [20同步方法及同步塊]
- 同步方法
- 同步塊
- 神奇的代碼例子1
- 神奇的代碼例子2
- [21CopyOnWriteArrayList]
- JUC
- [22死鎖]
- 死鎖是啥呢
- 來看代碼的解釋
- 卡死鎖了呢
- 解開死鎖啦
- 死鎖避免方法
- [23Lock鎖]
- 簡單介紹
- 代碼例子
- 總結
- synchronized與Lock的對比
- [24生產者消費者問題]
- 應用場景
- 執行緒通信-分析
- 幾個方法
- 怎嘛解決
- 解決方式1
- 解決方式2
- [25管程法]
- [26信號燈法]
- [27執行緒池]
- 使用執行緒池
- 代碼
- [28總結]
- 回顧總執行緒的創建
- 回顧其他
文章目錄
- java多執行緒總結
- @[toc]
- [03繼承Thread類]
- 三種創建方式
- Thread類
- [04網圖下載]
- 案例:下載圖片
- [05實作Runnable介面]
- Runnable介面
- 小結
- 繼承Thread類
- 實作runnable介面
- [06初識并發問題]
- 買票問題
- [07龜兔賽跑]
- 案例龜兔-race
- 代碼開始啦
- [08實作Callable介面]
- 了解即可
- [09靜態代理模式]
- 舉例
- 代碼實作
- 總結
- [10Lambda運算式]
- 簡單介紹lambda
- 函式式介面
- 代碼實作1
- 代碼實作2
- [11執行緒停止]
- 執行緒狀態
- 執行緒方法
- Stop
- [12休眠執行緒sleep]
- 代碼示例1
- 代碼示例2 倒計時
- 代碼示例3 時間表
- [13執行緒禮讓Yield]
- [14執行緒強制執行Join]
- [15觀測執行緒狀態]
- Thread.State
- [16執行緒的優先級]
- 內容
- 注意
- [17守護執行緒]
- deamon
- [18執行緒同步機制]
- [19三大不安全案例]
- 舉例,不安全的買票
- 舉例,不安全的取錢
- 舉例三
- [20同步方法及同步塊]
- 同步方法
- 同步塊
- 神奇的代碼例子1
- 神奇的代碼例子2
- [21CopyOnWriteArrayList]
- JUC
- [22死鎖]
- 死鎖是啥呢
- 來看代碼的解釋
- 卡死鎖了呢
- 解開死鎖啦
- 死鎖避免方法
- [23Lock鎖]
- 簡單介紹
- 代碼例子
- 總結
- synchronized與Lock的對比
- [24生產者消費者問題]
- 應用場景
- 執行緒通信-分析
- 幾個方法
- 怎嘛解決
- 解決方式1
- 解決方式2
- [25管程法]
- [26信號燈法]
- [27執行緒池]
- 使用執行緒池
- 代碼
- [28總結]
- 回顧總執行緒的創建
- 回顧其他
[03繼承Thread類]
三種創建方式
| Thread class | 繼承Thread類(重點) |
|---|---|
| Runnable介面 | 實作Runnable介面(重點) |
| Callable介面 | 實作Callable介面(了解) |
Thread類
- 自定義執行緒繼承Thread類
- **重寫run()**方法, 撰寫執行緒執行體
- 創建執行緒物件, 呼叫**start()**方法啟動執行緒
- 代碼例子:
package com.kuang.demo01;
//創建執行緒方式1:繼承Thread類,重寫run()方法,呼叫start開始執行緒
public class TestThread1 extends Thread{
@Override//養成好習慣,繼承完就重寫run方法,輸入run直接回車生產這個重寫方法
public void run() {
//run方法執行緒體
for (int i = 0; i < 20; i++) {
System.out.println("我在看代碼---" + i);
}
}
public static void main(String[] args) {
//main執行緒,主執行緒
//創建一個執行緒物件
TestThread1 testThread1 = new TestThread1();
//呼叫start()方法開啟執行緒
testThread1.start();
for (int i = 0; i < 20; i++) {
System.out.println("我在學習多執行緒---" + i);
}
}
}
- 跑起來的樣子: 每次跑起來的樣子都不太一樣~
我在學習多執行緒---0
我在學習多執行緒---1
我在學習多執行緒---2
我在學習多執行緒---3
我在學習多執行緒---4
我在學習多執行緒---5
我在學習多執行緒---6
我在學習多執行緒---7
我在學習多執行緒---8
我在學習多執行緒---9
我在看代碼---0
我在看代碼---1
我在看代碼---2
我在看代碼---3
我在看代碼---4
我在看代碼---5
我在看代碼---6
我在看代碼---7
我在看代碼---8
我在看代碼---9
我在看代碼---10
我在看代碼---11
我在看代碼---12
我在看代碼---13
我在看代碼---14
我在看代碼---15
我在看代碼---16
我在看代碼---17
我在看代碼---18
我在看代碼---19
我在學習多執行緒---10
我在學習多執行緒---11
我在學習多執行緒---12
我在學習多執行緒---13
我在學習多執行緒---14
我在學習多執行緒---15
我在學習多執行緒---16
我在學習多執行緒---17
我在學習多執行緒---18
我在學習多執行緒---19
行程已結束,退出代碼0
- 注意: 執行緒開啟不一定立即執行,
[04網圖下載]
案例:下載圖片
-
去百度下載commons-io,此處粘貼一個教程:commons_io下載教程
-
創建一個lib包, 把commons-io-2.8.0.jar拷到lib包里
-
右擊lib包, 點擊添加為庫….
-
寫代碼…
package com.kuang.demo01; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.URL; //練習Thread,實作多執行緒同步下載圖片 public class TestThread2 extends Thread{ private String url; //網路圖片地址 private String name; //保存的圖片名 public TestThread2(String url, String name){ this.url = url; this.name = name; } //下載圖片的執行體 @Override public void run() { WebDownloader webDownloader = new WebDownloader(); webDownloader.downloader(url, name); System.out.println("下載了檔案名為:"+name); } public static void main(String[] args) { TestThread2 t1 = new TestThread2("https://img-blog.csdnimg.cn/20210207180853481.jpg", "第一張圖片.jpg"); TestThread2 t2 = new TestThread2("https://img-blog.csdnimg.cn/20210207180853496.jpg", "第二張圖片.jpg"); TestThread2 t3 = new TestThread2("https://img-blog.csdnimg.cn/20210207180853466.jpg", "第三張圖片.jpg "); t1.start(); t2.start(); t3.start(); //如果用runnable介面,需要把extends換成runnable //然后把上面三行換成下面三行 //new Thread(t1).start(); //new Thread(t2).start(); //new Thread(t3).start(); } } //下載器 class WebDownloader{ //下載方法 public void downloader(String url, String name){ try { FileUtils.copyURLToFile(new URL(url), new File(name)); } catch (IOException e) { e.printStackTrace(); System.out.println("IO例外,downloader方法出現問題~"); } } } -
運行
下載了檔案名為:第一張圖片.jpg 下載了檔案名為:第三張圖片.jpg 下載了檔案名為:第二張圖片.jpg 行程已結束,退出代碼0
[05實作Runnable介面]
Runnable介面
- 定義MyRunnable類實作Runnable介面
- 實作**run()**方法,邊寫執行緒執行體
- 創建執行緒物件,呼叫**start()**方法啟動執行緒
- 寫代碼
package com.kuang.demo01;
//創建執行緒方式2:實作runnable介面,重寫run方法,
// 執行執行緒需要丟入runnable介面實作類,呼叫start
public class TestThread3 implements Runnable{
@Override
public void run() {
//run方法執行緒體
for (int i = 0; i < 20; i++) {
System.out.println("我在看代碼---"+i);
}
}
public static void main(String[] args) {
//創建runnable介面的實作類物件
TestThread3 testThread3 = new TestThread3();
//創建執行緒物件,通過執行緒物件來開啟我們的執行緒,代理
Thread thread = new Thread(testThread3);;
thread.start();
//以上可總結為
//new Thread(testThread3).start();
for (int i = 0; i < 20; i++) {
System.out.println("我在學習多執行緒---"+i);
}
}
}
- 運行
我在學習多執行緒---0
我在學習多執行緒---1
我在看代碼---0
我在學習多執行緒---2
我在看代碼---1
我在學習多執行緒---3
我在看代碼---2
我在學習多執行緒---4
我在看代碼---3
我在學習多執行緒---5
我在學習多執行緒---6
我在看代碼---4
我在看代碼---5
我在看代碼---6
我在看代碼---7
我在看代碼---8
我在看代碼---9
我在看代碼---10
我在看代碼---11
我在看代碼---12
我在看代碼---13
我在學習多執行緒---7
我在看代碼---14
我在看代碼---15
我在看代碼---16
我在看代碼---17
我在看代碼---18
我在看代碼---19
我在學習多執行緒---8
我在學習多執行緒---9
我在學習多執行緒---10
我在學習多執行緒---11
我在學習多執行緒---12
我在學習多執行緒---13
我在學習多執行緒---14
我在學習多執行緒---15
我在學習多執行緒---16
我在學習多執行緒---17
我在學習多執行緒---18
我在學習多執行緒---19
行程已結束,退出代碼0
小結
繼承Thread類
- 子類繼承Thread類具備多執行緒能力
- 啟動執行緒:子類物件.start()
- 不建議使用:避免OOP單繼承局限性
實作runnable介面
- 實作介面runnable具有多執行緒能力
- 啟動執行緒:傳入目標物件+Thread物件.start()
- 推薦使用:避免單繼承局限性,靈活方便,方便同一個物件被多個執行緒使用
[06初識并發問題]
買票問題
- 代碼
package com.kuang.demo01;
//多個執行緒同時操作一個物件
//買火車票的例子
public class TestThread4 implements Runnable {
//票數
private int ticketNums = 10;
@Override
public void run() {
while (true){
if(ticketNums<=0) {
break;
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"張票子~");
}
}
public static void main(String[] args) {
TestThread4 ticket = new TestThread4();
new Thread(ticket,"小明").start();
new Thread(ticket,"老師").start();
new Thread(ticket,"黃牛黨").start();
}
}
- 運行
老師拿到了第10張票子~
小明拿到了第9張票子~
小明拿到了第6張票子~
黃牛黨拿到了第8張票子~
黃牛黨拿到了第4張票子~
黃牛黨拿到了第3張票子~
小明拿到了第5張票子~
老師拿到了第7張票子~
小明拿到了第1張票子~
黃牛黨拿到了第2張票子~
行程已結束,退出代碼0
- 模擬延時
[在上面的那個代碼上加了一個延遲~]
package com.kuang.demo01;
//多個執行緒同時操作一個物件
//買火車票的例子
public class TestThread4 implements Runnable {
//票數
private int ticketNums = 10;
@Override
public void run() {
while (true){
if(ticketNums<=0) {
break;
}
//模擬延時,就是200毫秒,0.2秒
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"張票子~");
}
}
public static void main(String[] args) {
TestThread4 ticket = new TestThread4();
new Thread(ticket,"小明").start();
new Thread(ticket,"老師").start();
new Thread(ticket,"黃牛黨").start();
}
}
[然鵝,出現了問題,多個執行緒操作同一個資源的情況下,執行緒不安全,資料紊亂,這個問題以后再解決吧...]
黃牛黨拿到了第10張票子~
小明拿到了第8張票子~
老師拿到了第9張票子~
小明拿到了第7張票子~
黃牛黨拿到了第6張票子~
老師拿到了第5張票子~
老師拿到了第4張票子~
黃牛黨拿到了第3張票子~
小明拿到了第2張票子~
老師拿到了第1張票子~
黃牛黨拿到了第0張票子~
小明拿到了第-1張票子~
行程已結束,退出代碼0
[07龜兔賽跑]
案例龜兔-race
- 首先來個賽道距離,然后要離終點越來越近
- 判斷比賽是否結束
- 列印出勝利者
- 龜兔賽跑開始
- 故事中是烏龜贏的,因為兔子需要睡覺覺呀所有我們模擬兔子睡覺覺
- 終于,烏龜贏得比賽
代碼開始啦
代碼
package com.kuang.demo01;
//模擬龜兔賽跑
public class Race implements Runnable{
//勝利者
private static String winner;
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
//模擬兔子睡覺
if(Thread.currentThread().getName().equals("兔子")&&i%10==0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//判斷比賽是否結束
boolean flag = gameOver(i);
//如果比賽結束了,就停止程式
if(flag){
break;
}
System.out.println(Thread.currentThread().getName()+"--->跑了"+i+"步");
}
}
//判斷是否完成比賽
private boolean gameOver(int steps){
//販毒案是否有勝利者
if(winner!=null){//已經存在勝利者了
return true;
}{
if(steps>=100){
winner = Thread.currentThread().getName();
System.out.println("winner is"+winner);
}
}
return false;
}
public static void main(String[] args) {
Race race = new Race();
new Thread(race,"兔子子").start();
new Thread(race,"烏龜").start();
}
}
結果, 我的兔子太能跑了, 不管睡了多久都能勝利, 唉, 這可能就是天賦的魅力吧, 所以我把兔子黑幕, 讓它睡的時間超級長, 終于,烏龜贏啦!歡呼!雀躍!
兔子子--->跑了0步
烏龜--->跑了0步
兔子子--->跑了1步
兔子子--->跑了2步
兔子子--->跑了3步
兔子子--->跑了4步
兔子子--->跑了5步
兔子子--->跑了6步
兔子子--->跑了7步
兔子子--->跑了8步
兔子子--->跑了9步
兔子子--->跑了10步
兔子子--->跑了11步
兔子子--->跑了12步
兔子子--->跑了13步
兔子子--->跑了14步
兔子子--->跑了15步
兔子子--->跑了16步
兔子子--->跑了17步
烏龜--->跑了1步
烏龜--->跑了2步
烏龜--->跑了3步
烏龜--->跑了4步
烏龜--->跑了5步
烏龜--->跑了6步
烏龜--->跑了7步
烏龜--->跑了8步
烏龜--->跑了9步
烏龜--->跑了10步
烏龜--->跑了11步
烏龜--->跑了12步
烏龜--->跑了13步
烏龜--->跑了14步
烏龜--->跑了15步
烏龜--->跑了16步
烏龜--->跑了17步
烏龜--->跑了18步
烏龜--->跑了19步
烏龜--->跑了20步
烏龜--->跑了21步
烏龜--->跑了22步
烏龜--->跑了23步
烏龜--->跑了24步
烏龜--->跑了25步
烏龜--->跑了26步
烏龜--->跑了27步
烏龜--->跑了28步
兔子子--->跑了18步
烏龜--->跑了29步
兔子子--->跑了19步
烏龜--->跑了30步
烏龜--->跑了31步
烏龜--->跑了32步
烏龜--->跑了33步
烏龜--->跑了34步
烏龜--->跑了35步
兔子子--->跑了20步
兔子子--->跑了21步
兔子子--->跑了22步
烏龜--->跑了36步
烏龜--->跑了37步
烏龜--->跑了38步
兔子子--->跑了23步
兔子子--->跑了24步
烏龜--->跑了39步
烏龜--->跑了40步
烏龜--->跑了41步
烏龜--->跑了42步
烏龜--->跑了43步
烏龜--->跑了44步
烏龜--->跑了45步
烏龜--->跑了46步
兔子子--->跑了25步
烏龜--->跑了47步
兔子子--->跑了26步
兔子子--->跑了27步
烏龜--->跑了48步
兔子子--->跑了28步
烏龜--->跑了49步
兔子子--->跑了29步
烏龜--->跑了50步
兔子子--->跑了30步
烏龜--->跑了51步
兔子子--->跑了31步
烏龜--->跑了52步
兔子子--->跑了32步
烏龜--->跑了53步
兔子子--->跑了33步
烏龜--->跑了54步
兔子子--->跑了34步
烏龜--->跑了55步
兔子子--->跑了35步
烏龜--->跑了56步
兔子子--->跑了36步
烏龜--->跑了57步
兔子子--->跑了37步
烏龜--->跑了58步
兔子子--->跑了38步
烏龜--->跑了59步
兔子子--->跑了39步
烏龜--->跑了60步
烏龜--->跑了61步
兔子子--->跑了40步
烏龜--->跑了62步
兔子子--->跑了41步
烏龜--->跑了63步
兔子子--->跑了42步
烏龜--->跑了64步
兔子子--->跑了43步
烏龜--->跑了65步
烏龜--->跑了66步
烏龜--->跑了67步
烏龜--->跑了68步
烏龜--->跑了69步
烏龜--->跑了70步
烏龜--->跑了71步
烏龜--->跑了72步
兔子子--->跑了44步
烏龜--->跑了73步
兔子子--->跑了45步
烏龜--->跑了74步
兔子子--->跑了46步
烏龜--->跑了75步
兔子子--->跑了47步
烏龜--->跑了76步
兔子子--->跑了48步
烏龜--->跑了77步
兔子子--->跑了49步
烏龜--->跑了78步
兔子子--->跑了50步
烏龜--->跑了79步
兔子子--->跑了51步
烏龜--->跑了80步
兔子子--->跑了52步
烏龜--->跑了81步
兔子子--->跑了53步
烏龜--->跑了82步
兔子子--->跑了54步
烏龜--->跑了83步
兔子子--->跑了55步
烏龜--->跑了84步
兔子子--->跑了56步
烏龜--->跑了85步
兔子子--->跑了57步
烏龜--->跑了86步
兔子子--->跑了58步
烏龜--->跑了87步
兔子子--->跑了59步
烏龜--->跑了88步
兔子子--->跑了60步
兔子子--->跑了61步
兔子子--->跑了62步
兔子子--->跑了63步
兔子子--->跑了64步
兔子子--->跑了65步
兔子子--->跑了66步
兔子子--->跑了67步
兔子子--->跑了68步
兔子子--->跑了69步
兔子子--->跑了70步
烏龜--->跑了89步
烏龜--->跑了90步
烏龜--->跑了91步
烏龜--->跑了92步
烏龜--->跑了93步
烏龜--->跑了94步
烏龜--->跑了95步
烏龜--->跑了96步
烏龜--->跑了97步
烏龜--->跑了98步
烏龜--->跑了99步
winner is烏龜
烏龜--->跑了100步
兔子子--->跑了71步
行程已結束,退出代碼0
我發現我不僅是一只狗子, 還是一個烏龜嗚嗚嗚~, 多執行緒太難了, 腦瓜子疼, 兄弟們, 奧里給!
[08實作Callable介面]
了解即可
- 實作Callable介面, 需要回傳值型別
- 重寫Call方法, 需要拋出例外
- 創建目標物件
- 創建執行任務: ExecutorService ser = Executors.newFixedThreadPool(1);
- 提交執行: Futureresult1 = ser.submit(t1);
- 獲取結果: boolean r1 = result1.get()
- 關閉服務: ser.shutdownNow();
- 代碼
package com.kuang.demo02;
//執行緒創建方式三:實作callable的介面
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;
public class TestCallable implements Callable<Boolean> {
private String url; //網路圖片地址
private String name; //保存的圖片名
public TestCallable(String url, String name) {
this.url = url;
this.name = name;
}
//下載圖片的執行體
@Override
public Boolean call() {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url, name);
System.out.println("下載了檔案名為:" + name);
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable t1 = new TestCallable("https://img-blog.csdnimg.cn/20210207180853481.jpg", "第一張圖片.jpg");
TestCallable t2 = new TestCallable("https://img-blog.csdnimg.cn/20210207180853496.jpg", "第二張圖片.jpg");
TestCallable t3 = new TestCallable("https://img-blog.csdnimg.cn/20210207180853466.jpg", "第三張圖片.jpg");
// 創建執行任務:
ExecutorService ser = Executors.newFixedThreadPool(3);
// 提交執行:
Future<Boolean> r1 = ser.submit(t1);
Future<Boolean> r2 = ser.submit(t2);
Future<Boolean> r3 = ser.submit(t3);
// 獲取結果:
boolean rs1 = r1.get();
boolean rs2 = r2.get();
boolean rs3 = r3.get();
System.out.println(rs1);
System.out.println(rs2);
System.out.println(rs3);
// 關閉服務:
ser.shutdownNow();
}
//下載器
class WebDownloader {
//下載方法
public void downloader(String url, String name) {
try {
FileUtils.copyURLToFile(new URL(url), new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("IO例外,downloader方法出現問題~");
}
}
}
}
運行
下載了檔案名為:第一張圖片.jpg
下載了檔案名為:第三張圖片.jpg
下載了檔案名為:第二張圖片.jpg
true
true
true
行程已結束,退出代碼0
[09靜態代理模式]
舉例
結婚
- 你:真實角色
- 婚慶公司:代理你, 幫你處理結婚的事情
- 結婚: 實作都實作結婚介面即可
代碼實作
package com.kuang.demo01;
public class StaticProxy {
public static void main(String[] args) {
new Thread(()-> System.out.println("我愛你")).start();
new WeddingCompany(new You()).HappyMarry();
//上面一句代替下面兩句
// WeddingCompany weddingCompany = new WeddingCompany(new You());
// weddingCompany.HappyMarry();
}
}
interface Marry{
//人間四大喜事
//久旱逢甘露
//他鄉遇故知
//洞房花燭夜
//金榜題名時
void HappyMarry();
}
//真實角色, 你去結婚
class You implements Marry{
@Override
public void HappyMarry() {
System.out.println("秦老師要結婚了,超開心~");
}
}
//代理角色,幫助你去結婚
class WeddingCompany implements Marry{
private Marry target;
public WeddingCompany(Marry target){
this.target = target;
}
@Override
public void HappyMarry() {
before();
this.target.HappyMarry();
after();
}
private void before(){
System.out.println("結婚之前, 布置現場");
}
private void after(){
System.out.println("結婚之后,收尾款");
}
}
[跑起來]
我愛你
結婚之前, 布置現場
秦老師要結婚了,超開心~
結婚之后,收尾款
行程已結束,退出代碼0
總結
- 真實物件和代理物件都要實作同一個介面
- 代替物件要代理真實角色
- 代理物件可以做很多真實物件做不了的事情
- 真實物件專注做自己的事情
[10Lambda運算式]
簡單介紹lambda
-
λ希臘字母表中排序第十一位的字母,英文名為Lambda
-
避免匿名內部類定義過多
-
其實質屬于函式式編程的概念
(params)->expression[運算式](params)->statement[陳述句](params)->{statement} -
new Thread (()->System.out.println("多執行緒學習...")).start();
函式式介面
- 理解Functional Interface(函式式介面), 是學習Java8 lambda運算式的關鍵所在
- 函式式介面的定義
- 任何介面,如果只包含唯一一個抽象方法, 那么它就是一個函式式介面
- 對于函式式介面,我么可以通過lambda運算式來創建該介面的物件
代碼實作1
package com.kuang.demo01;
/*
推到lambda運算式
*/
public class TestLambda {
//3.靜態內部類
static class Like2 implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda2");
}
}
public static void main(String[] args) {
ILike like = new Like();
like.lambda();
like = new Like2();
like.lambda();
//4.區域內部類
class Like3 implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda3");
}
}
like = new Like3();
like.lambda();
//5.匿名內部類,沒有類的名稱,必須借助介面或者父類
like = new ILike() {
@Override
public void lambda() {
System.out.println("i like lambda4");
}
};
like.lambda();
//6.用lambda簡化
like = ()->{
System.out.println("i like lambda5");
};
like.lambda();
}
}
//1.定義一個函式式介面
interface ILike{
void lambda();
}
//2.實作類
class Like implements ILike{
@Override
public void lambda() {
System.out.println("i like lambda");
}
}
[run~]
i like lambda
i like lambda2
i like lambda3
i like lambda4
i like lambda5
行程已結束,退出代碼0
代碼實作2
這次來分步實作
- 創建ILove介面,創建Love類
package com.kuang.demo01;
public class TestLambda2 {
public static void main(String[] args) {
ILove love = new Love();
love.love(1);
}
}
interface ILove{
void love(int a);
}
class Love implements ILove{
@Override
public void love(int a) {
System.out.println("i love you-->"+a);
}
}
- 把Love類放到class TestLambda2里面,在Love類前面加static
package com.kuang.demo01;
public class TestLambda2 {
static class Love implements ILove{
@Override
public void love(int a) {
System.out.println("i love you-->"+a);
}
}
public static void main(String[] args) {
ILove love = new Love();
love.love(2);
}
}
interface ILove{
void love(int a);
}
- 把class去掉static, 放到main方法里面
package com.kuang.demo01;
public class TestLambda2 {
public static void main(String[] args) {
class Love implements ILove{
@Override
public void love(int a) {
System.out.println("i love you-->"+a);
}
}
ILove love = new Love();
love.love(3);
}
}
interface ILove{
void love(int a);
}
- 匿名內部類
package com.kuang.demo01;
public class TestLambda2 {
public static void main(String[] args) {
ILove love = new ILove(){
@Override
public void love(int a) {
System.out.println("i love you-->"+a);
}
};
love.love(3);
}
}
interface ILove{
void love(int a);
}
- lambda
package com.kuang.demo01;
public class TestLambda2 {
public static void main(String[] args) {
ILove love = (int a) -> {
System.out.println("i love you-->"+a);
};
love.love(520);
}
}
interface ILove{
void love(int a);
}
- 簡化一,去掉int
package com.kuang.demo01;
public class TestLambda2 {
public static void main(String[] args) {
ILove love = (a) -> {
System.out.println("i love you-->"+a);
};
love.love(520);
}
}
interface ILove{
void love(int a);
}
- 簡化二.去掉括號,(只有一個引數可去)
package com.kuang.demo01;
public class TestLambda2 {
public static void main(String[] args) {
ILove love = a -> {
System.out.println("i love you-->"+a);
};
love.love(520);
}
}
interface ILove{
void love(int a);
}
- 簡化三,去掉花括號(代碼只有一行可去)
package com.kuang.demo01;
public class TestLambda2 {
public static void main(String[] args) {
ILove love = a -> System.out.println("i love you-->"+a);
love.love(520);
}
}
interface ILove{
void love(int a);
}
[11執行緒停止]
執行緒狀態
創建狀態, 就緒狀態, 阻塞狀態, 運行狀態, 死亡狀態
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-UdbaHzmy-1612980251037)(C:\Users\段+7\Pictures\ppt\螢屏截圖 2021-02-08 165145.png)]
執行緒方法
| 方法 | 說明 |
|---|---|
| setPriority(int newPriority) | 更改執行緒的優先級 |
| static void sleep(long millis) | 在指定的毫秒內讓當前正在執行的執行緒休眠 |
| void join() | 等待該執行緒終止 |
| static void yield() | 暫停當前正在執行的執行緒物件, 并執行其他執行緒 |
| void interrupt() | 中斷執行緒, 別用這個方式 |
| boolean isAlive() | 測驗執行緒是否處于活躍狀態 |
Stop
- 建議執行緒正常停止—>利用次數, 不建議死回圈
- 建議使用標志位—>設定一個標志位
- 不要使用stop或者destory等過時或者JDK不建議使用的方法
- 不推薦使用JDK提供的stop(), destory()方法, 因為已廢棄
- 推薦執行緒自己停下來
- 建議使用一個標志位進行終止變數, 當flag= false, 則終止執行緒運行
package com.kuang.demo01;
public class TestStop implements Runnable{
//1.設定一個標識位
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag){
System.out.println("run...Thread"+i++);
}
}
//2.設定一個公開的方法暫停執行緒, 轉換標志位
public void stop(){
this.flag = false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
new Thread(testStop).start();
for (int i = 0; i < 1000; i++) {
System.out.println("main"+i);
if(i==900){
//呼叫stop方法切換標志位,讓執行緒停止
testStop.stop();
System.out.println("該執行緒停止了");
}
}
}
}
[run]
main0
main1
main2
main3
main4
main5
main6
main7
main8
main9
main10
main11
main12
main13
main14
main15
main16
main17
main18
main19
main20
main21
main22
main23
main24
main25
main26
main27
main28
main29
main30
main31
main32
main33
main34
main35
main36
main37
main38
main39
main40
main41
main42
main43
main44
main45
main46
main47
main48
main49
main50
main51
main52
main53
main54
main55
main56
main57
main58
main59
main60
main61
main62
main63
main64
main65
main66
main67
main68
main69
main70
main71
main72
main73
main74
main75
main76
main77
main78
main79
main80
main81
main82
main83
main84
main85
main86
main87
main88
main89
main90
main91
main92
main93
main94
main95
main96
main97
main98
main99
run...Thread0
run...Thread1
run...Thread2
run...Thread3
run...Thread4
run...Thread5
run...Thread6
run...Thread7
run...Thread8
run...Thread9
run...Thread10
run...Thread11
run...Thread12
run...Thread13
run...Thread14
run...Thread15
run...Thread16
run...Thread17
run...Thread18
main100
run...Thread19
main101
run...Thread20
run...Thread21
run...Thread22
run...Thread23
main102
run...Thread24
run...Thread25
run...Thread26
run...Thread27
run...Thread28
run...Thread29
main103
main104
main105
main106
main107
main108
main109
main110
main111
main112
main113
main114
main115
main116
main117
main118
main119
run...Thread30
run...Thread31
run...Thread32
run...Thread33
run...Thread34
run...Thread35
run...Thread36
run...Thread37
run...Thread38
run...Thread39
run...Thread40
run...Thread41
run...Thread42
run...Thread43
run...Thread44
run...Thread45
run...Thread46
main120
main121
main122
main123
main124
main125
main126
main127
main128
main129
main130
main131
main132
main133
main134
main135
main136
main137
main138
main139
main140
main141
main142
main143
main144
main145
main146
main147
main148
main149
main150
main151
main152
main153
main154
main155
main156
main157
main158
main159
main160
main161
main162
main163
main164
main165
main166
main167
main168
main169
main170
main171
main172
main173
main174
main175
main176
main177
main178
main179
main180
main181
main182
main183
main184
main185
main186
main187
main188
main189
main190
main191
main192
main193
main194
main195
main196
main197
main198
main199
main200
main201
main202
main203
main204
main205
main206
main207
main208
main209
main210
main211
main212
main213
main214
main215
main216
main217
main218
main219
main220
main221
main222
main223
main224
main225
main226
main227
main228
main229
main230
main231
main232
main233
main234
main235
main236
main237
main238
main239
main240
main241
main242
main243
main244
main245
main246
main247
main248
main249
main250
main251
main252
main253
main254
main255
main256
main257
main258
main259
main260
main261
main262
main263
main264
main265
main266
main267
main268
main269
main270
main271
main272
main273
main274
main275
main276
main277
main278
main279
main280
main281
main282
main283
main284
main285
main286
main287
main288
main289
main290
main291
main292
main293
main294
main295
main296
main297
main298
main299
main300
main301
main302
main303
main304
main305
main306
main307
main308
main309
main310
main311
main312
main313
main314
main315
main316
main317
main318
main319
main320
main321
main322
main323
main324
main325
main326
main327
main328
main329
main330
main331
main332
main333
main334
main335
main336
main337
main338
main339
main340
main341
main342
main343
main344
main345
main346
main347
main348
main349
main350
main351
main352
main353
main354
main355
main356
main357
main358
main359
main360
main361
main362
main363
main364
main365
main366
main367
main368
main369
main370
main371
main372
main373
main374
main375
main376
main377
main378
main379
main380
main381
main382
main383
main384
main385
main386
main387
main388
main389
main390
main391
main392
main393
main394
main395
main396
main397
main398
main399
main400
main401
main402
main403
main404
main405
main406
main407
main408
main409
main410
main411
main412
main413
main414
main415
main416
main417
main418
main419
main420
main421
main422
main423
main424
main425
main426
main427
main428
main429
main430
main431
main432
main433
main434
main435
main436
main437
main438
main439
main440
main441
main442
main443
main444
main445
main446
main447
main448
main449
main450
main451
main452
main453
main454
main455
main456
main457
main458
main459
main460
main461
main462
main463
main464
main465
main466
main467
main468
main469
main470
main471
main472
main473
main474
main475
main476
main477
main478
main479
main480
main481
main482
main483
main484
main485
main486
main487
main488
main489
main490
main491
main492
main493
main494
main495
main496
main497
main498
main499
main500
main501
main502
main503
main504
main505
main506
main507
main508
main509
main510
main511
main512
main513
main514
main515
main516
main517
main518
main519
main520
main521
main522
main523
main524
main525
main526
main527
main528
main529
main530
main531
main532
main533
main534
main535
main536
main537
main538
main539
main540
main541
main542
main543
main544
main545
main546
main547
main548
main549
main550
main551
main552
main553
main554
main555
main556
main557
main558
main559
main560
main561
main562
main563
main564
main565
main566
main567
main568
main569
main570
main571
main572
main573
main574
main575
main576
main577
main578
main579
main580
main581
main582
main583
main584
main585
main586
main587
main588
main589
main590
main591
main592
main593
main594
main595
main596
main597
main598
main599
main600
main601
main602
main603
main604
main605
main606
main607
main608
main609
main610
main611
main612
main613
main614
main615
main616
main617
main618
main619
main620
main621
main622
main623
main624
main625
main626
main627
main628
main629
main630
run...Thread47
main631
main632
main633
main634
main635
main636
main637
main638
main639
main640
main641
main642
main643
main644
main645
main646
main647
main648
main649
main650
main651
main652
main653
main654
main655
main656
main657
main658
main659
main660
main661
main662
main663
main664
main665
main666
main667
main668
main669
main670
main671
main672
main673
main674
main675
main676
main677
main678
main679
main680
main681
main682
main683
main684
main685
main686
main687
main688
main689
main690
main691
main692
main693
main694
main695
main696
main697
main698
main699
main700
main701
main702
main703
main704
main705
main706
main707
main708
main709
main710
main711
main712
main713
main714
main715
main716
main717
main718
main719
main720
main721
main722
main723
main724
main725
main726
main727
main728
main729
main730
main731
main732
main733
main734
main735
main736
main737
main738
main739
main740
main741
main742
main743
main744
main745
main746
main747
main748
main749
main750
main751
main752
main753
main754
main755
main756
main757
main758
main759
main760
main761
main762
main763
main764
main765
main766
main767
main768
main769
main770
main771
main772
main773
main774
main775
main776
main777
main778
main779
main780
main781
main782
main783
main784
main785
main786
main787
main788
main789
main790
main791
main792
main793
main794
main795
main796
main797
main798
main799
main800
main801
main802
main803
main804
main805
main806
main807
main808
main809
main810
main811
main812
main813
main814
main815
main816
main817
main818
main819
main820
main821
main822
main823
main824
main825
main826
main827
main828
main829
main830
main831
main832
main833
main834
main835
main836
main837
main838
main839
main840
main841
main842
main843
main844
main845
main846
main847
main848
main849
main850
main851
main852
main853
main854
main855
main856
main857
main858
main859
main860
main861
main862
main863
main864
main865
main866
main867
main868
main869
main870
main871
main872
main873
main874
main875
main876
main877
main878
main879
main880
main881
main882
main883
main884
main885
main886
main887
main888
main889
main890
main891
main892
main893
main894
main895
main896
main897
main898
main899
main900
該執行緒停止了
main901
main902
main903
main904
main905
main906
main907
main908
main909
main910
main911
main912
main913
main914
main915
main916
main917
main918
main919
main920
main921
main922
main923
main924
main925
main926
main927
main928
main929
main930
main931
main932
main933
main934
main935
main936
main937
main938
main939
main940
main941
main942
main943
main944
main945
main946
main947
main948
main949
main950
main951
main952
main953
main954
main955
main956
main957
main958
main959
main960
main961
main962
main963
main964
main965
main966
main967
main968
main969
main970
main971
main972
main973
main974
main975
main976
main977
run...Thread48
main978
main979
main980
main981
main982
main983
main984
main985
main986
main987
main988
main989
main990
main991
main992
main993
main994
main995
main996
main997
main998
main999
行程已結束,退出代碼0
[12休眠執行緒sleep]
- sleep(時間)指定當前執行緒阻塞的毫秒數
- sleep存在例外InterruptedException
- sleep時間到達后執行緒進入就緒狀態
- sleep可以模擬網路延時, 倒計時等
- 每一個物件都有一個鎖, sleep不不會釋放鎖
- 模擬網路延時: 放大問題的發生性
代碼示例1
上面的黃牛黨買票問題, 再發一遍嘿嘿嘿
package com.kuang.demo01;
//多個執行緒同時操作一個物件
//買火車票的例子
public class TestThread4 implements Runnable {
//票數
private int ticketNums = 10;
@Override
public void run() {
while (true){
if(ticketNums<=0) {
break;
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"張票子~");
}
}
public static void main(String[] args) {
TestThread4 ticket = new TestThread4();
new Thread(ticket,"小明").start();
new Thread(ticket,"老師").start();
new Thread(ticket,"黃牛黨").start();
}
}
[run]
老師拿到了第10張票子~
小明拿到了第9張票子~
小明拿到了第6張票子~
黃牛黨拿到了第8張票子~
黃牛黨拿到了第4張票子~
黃牛黨拿到了第3張票子~
小明拿到了第5張票子~
老師拿到了第7張票子~
小明拿到了第1張票子~
黃牛黨拿到了第2張票子~
行程已結束,退出代碼0
代碼示例2 倒計時
package com.kuang.demo01;
//模擬倒計時
public class TestSleep2 {
public static void main(String[] args) {
try {
tenDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//模擬倒計時
public static void tenDown() throws InterruptedException {
int num = 10;
while(true){
Thread.sleep(1000);
System.out.println(num--);
if(num<=0){
break;
}
}
}
}
[運行]每一秒出一個數
10
9
8
7
6
5
4
3
2
1
行程已結束,退出代碼0
代碼示例3 時間表
package com.kuang.demo01;
import java.text.SimpleDateFormat;
import java.util.Date;
//模擬倒計時
public class TestSleep2 {
public static void main(String[] args) {
//列印當前時間
Date startTime = new Date(System.currentTimeMillis());//獲取當前系統時間
while (true) {
try {
Thread.sleep(1000);
System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
startTime = new Date(System.currentTimeMillis());//更新時間
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
[運行]自己去試試吧嘿嘿嘿~
18:26:43
18:26:44
18:26:45
18:26:46
18:26:47
18:26:48
18:26:49
18:26:50
18:26:51
...
[13執行緒禮讓Yield]
- 禮讓執行緒, 讓當前正在執行的執行緒暫停, 但不阻塞
- 將執行緒從運行狀態轉為就緒狀態
- 讓cpu重新調度, 禮讓不一定成功! 看cpu心情
package com.kuang.demo01;
public class TestYield {
public static void main(String[] args) {
MyYield myYield = new MyYield();
new Thread(myYield,"a").start();
new Thread(myYield,"b").start();
}
}
class MyYield implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"執行緒開始執行");
Thread.yield();//禮讓
System.out.println(Thread.currentThread().getName()+"執行緒停止執行");
}
}
[運行~]禮讓成功
a執行緒開始執行
b執行緒開始執行
b執行緒停止執行
a執行緒停止執行
行程已結束,退出代碼0
[14執行緒強制執行Join]
- join合并執行緒, 待此執行緒執行完成后, 再執行其他執行緒, 其他執行緒阻塞
- 可以想象成插隊
package com.kuang.demo01;
//插隊~
public class TestJoin implements Runnable {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("執行緒vip來了..."+i);
}
}
public static void main(String[] args) throws InterruptedException {
//啟動我們的執行緒
TestJoin testJoin = new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
//主執行緒
for (int i = 0; i < 500; i++) {
if(i==200){
thread.join();//插隊
}
System.out.println("main"+i);
}
}
}
//就是vip在200之前,兩個執行緒一起執行,200后vip一直執行到1000,然后main運行
[15觀測執行緒狀態]
Thread.State
執行緒狀態. 執行緒可以處于以下狀態之一
new尚未啟動的執行緒處于此狀態RUNNABLE在java虛擬機中執行的執行緒處于此狀態BLOCKED被阻塞等待監視器鎖定的執行緒處于此狀態WAITING正在等待另一個執行緒執行特定動作的執行緒處于此狀態TIMED_WAITING正在等待另一個執行緒執行動作達到指定等待時間的執行緒處于此狀態TERMINATED已退出的執行緒處于此狀態
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-12cl4c6Z-1612980251038)(C:\Users\段+7\Pictures\ppt\螢屏截圖 2021-02-08 165145.png)]
package com.kuang.demo01;
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("");
});
//觀察狀態
Thread.State state = thread.getState();
System.out.println(state);//NEW
//觀察啟動后
thread.start();//啟動執行緒
state = thread.getState();
System.out.println(state);//Run
while(state!=Thread.State.TERMINATED){//只要執行緒不終止,就一直輸出狀態
Thread.sleep(100);
state = thread.getState();//更新執行緒狀態
System.out.println(state);//輸出狀態
}
}
}
[run~]
NEW
RUNNABLE
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TIMED_WAITING
TERMINATED
行程已結束,退出代碼0
[16執行緒的優先級]
內容
- java提供一個執行緒調度器來監控程式中啟動后進入就緒狀態的所有執行緒, 執行緒調度器按照優先級決定應該調度哪個執行緒來執行
- 執行緒的優先級用數字表示, 范圍從1~10
- Thread.MIN_PRIORITY = 1;
- Thread.MAX_PRIORITY = 10;
- Thread.NORM_PRIORITY = 5;
- 使用一下方式改變或獲取優先級
- getPriority().setPriority(int xxx)
package com.kuang.demo01;
//測驗執行緒的優先級
public class TestPriority {
public static void main(String[] args) {
//主執行緒默認優先級
System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
MyPriority myPriority = new MyPriority();
Thread t1 = new Thread(myPriority);
Thread t2 = new Thread(myPriority);
Thread t3 = new Thread(myPriority);
Thread t4 = new Thread(myPriority);
Thread t5 = new Thread(myPriority);
Thread t6 = new Thread(myPriority);
//先設定優先級,再啟動
t1.start();
t2.setPriority(1);
t2.start();
t3.setPriority(4);
t3.start();
t4.setPriority(Thread.MAX_PRIORITY);
t4.start();
t5.setPriority(5);
t5.start();
t6.setPriority(9);
t6.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
}
}
[run]
main--->5
Thread-0--->5
Thread-3--->10
Thread-2--->4
Thread-4--->5
Thread-5--->9
Thread-1--->1
行程已結束,退出代碼0
注意
優先級低只意味著獲得調度的概率低, 并不是優先級低就不會被呼叫了, 這都是看CPU的調度
[17守護執行緒]
deamon
- 執行緒分為用戶執行緒和守護執行緒
- 虛擬機必須確保用戶執行緒執行完畢
- 虛擬機不用等待守護執行緒執行完畢
- 如, 后臺記錄操作日志, 監控記憶體, 垃圾回收等等…
package com.kuang.demo01;
public class TestDaemon {
public static void main(String[] args) {
God god = new God();
You you = new You();
Thread thread = new Thread(god);
thread.setDaemon(true);//默認是false表示是用戶執行緒, 正常執行緒都是用戶執行緒
thread.start();
new Thread(you).start();//你 用戶執行緒啟動
}
}
//上帝
class God implements Runnable{
@Override
public void run() {
while(true){
System.out.println("上帝保佑著你");
}
}
}
//你
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 36500; i++) {
System.out.println("你一生都開心的活著");
}
System.out.println("-=========goodbye world!===========-");//hello world!
}
}
[run]
上帝保佑著你
上帝保佑著你
上帝保佑著你
你一生都開心的活著
你一生都開心的活著
...
你一生都開心的活著
上帝保佑著你
上帝保佑著你
...
上帝保佑著你
-=========goodbye world!===========-
上帝保佑著你
上帝保佑著你
...
上帝保佑著你
上帝保佑著你
行程已結束,退出代碼0
[18執行緒同步機制]
多個執行緒操作同一個資源
舉個栗子
- 上萬人同時搶100張票
- 兩個銀行同時取錢
- 顯示生活中, 我們會遇到"同一個資源, 多個人都想使用"的問題, 比如, 食堂排隊打飯, 每個人都想吃飯, 每個人都想吃飯, 最天然的解決辦法就是, 排隊, 一個一個來
- 處理多執行緒問題時, 多個執行緒訪問同一個物件, 并且某些執行緒還想修改這個物件, 這時候我們就需要執行緒同步, 執行緒同步其實就是一種等待機制, 多個需要同時訪問此物件的執行緒進入這個物件的等待池形成佇列, 等待前面執行緒使用完畢, 下一個執行緒再使用
鎖
比如上廁所需要排隊, 進廁所我們要把門鎖上, 如果沒有鎖, 那后面的人還會進去, 排隊將沒啥用了, 所以我們需要鎖~
形成條件:佇列+鎖
執行緒同步
由于同一行程的多個執行緒共享同一塊存盤空間, 在帶來方便的同時, 也帶來了訪問沖突, 為了保證資料在方法中被訪問時的正確性, 在訪問時加入鎖機制synchronized, 當一個執行緒獲得物件的排它鎖, 獨占資源, 其他執行緒必須等待, 使用后釋放鎖即可, 存在以下問題:
- 一個執行緒持有鎖會導致其他所有需要此鎖的執行緒掛起
- 在多執行緒競爭下, 加鎖, 釋放鎖會導致比較多的背景關系切換和調度延時, 引起性能問題
- 如果一個優先級高的執行緒等待有一個優先級低的執行緒釋放鎖, 或導致優先級倒置, 引起性能問題
[19三大不安全案例]
舉例,不安全的買票
代碼及運行:
[代碼]
package com.kuang.syn;
//不安全的買票
//執行緒不安全,有負數
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket station = new BuyTicket();
new Thread(station,"苦逼的我").start();
new Thread(station,"牛逼的你們").start();
new Thread(station,"可惡的黃牛黨").start();
}
}
class BuyTicket implements Runnable{
//票
int tickerNums = 10;
boolean flag = true;//外部停止方式
@Override
public void run() {
//買票
while (flag){
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void buy() throws InterruptedException {
//判斷是否有票
if(tickerNums<=0){
return;
}
//模擬延時
Thread.sleep(100);
//買票
System.out.println(Thread.currentThread().getName()+"拿到"+tickerNums--);
}
}
[運行]
可惡的黃牛黨拿到10
苦逼的我拿到9
牛逼的你們拿到8
苦逼的我拿到7
牛逼的你們拿到6
可惡的黃牛黨拿到5
苦逼的我拿到4
牛逼的你們拿到2
可惡的黃牛黨拿到3
苦逼的我拿到1
牛逼的你們拿到0
可惡的黃牛黨拿到-1
上面代碼出現了拿到第0張票和第-1張票的情況, 這種情況不應該出現, 這也說明我們的執行緒不安全, 因為我們沒排隊, 所有人都看到最后一張票, 都去搶, 最后一張票三個人都搶到了, 所有, 這也不行呀~
舉例,不安全的取錢
sleep可以放大問題
package com.kuang.syn;
//不安全的取錢
//兩個人去銀行取錢,賬戶
public class UnsafeBank {
public static void main(String[] args) {
//賬戶
Account account = new Account(100, "結婚基金");
Drawing you = new Drawing(account, 50, "你");
Drawing girlFriend = new Drawing(account, 100, "girlFriend");
you.start();
girlFriend.start();
}
}
//賬戶
class Account{
int money;//余額
String name; //卡名
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
//銀行:模擬取款
class Drawing extends Thread{
Account account;//賬戶
//取了多少錢
int drawingMoney;
//現在手里有多少錢
int nowMoney;
public Drawing(Account account, int drawingMoney, String name){
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
//取錢
@Override
public void run() {
//判斷有沒有錢
if(account.money-drawingMoney<0){
System.out.println("錢不夠, 取不了");
return;
}
//模擬延時
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡內余額
account.money = account.money - drawingMoney;
//手里的錢
nowMoney = nowMoney + drawingMoney;
System.out.println("余額為"+account.money);
System.out.println(this.getName()+"手里的錢"+nowMoney);
}
}
[run]
余額為-50
girlFriend手里的錢100
余額為-50
你手里的錢50
行程已結束,退出代碼0
舉例三
這個看不懂…枯了
package com.kuang.syn;
import java.util.ArrayList;
import java.util.List;
//執行緒不安全的集合
public class UnsafeList {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
[run]
9999
行程已結束,退出代碼0
[20同步方法及同步塊]
同步方法
-
由于我們可以通過private關鍵字來保證資料物件只能被方法訪問, 所以我們只需要針對方法提出一套機制, 這套機制就是synchronized關鍵字, 它包括兩種用法: synchronized方法和synchronized塊
同步方法
public synchronized void method(int args){} -
synchronized方法控制對"物件"的訪問, 每個物件對應一把鎖, 每個synchronized方法都必須獲得呼叫該方法的物件的鎖才能執行, 否則執行緒會阻塞, 方法一旦執行, 就獨占該鎖, 知道該方法回傳才釋放鎖, 后面被阻塞的執行緒才能獲得這個鎖, 繼續執行
缺陷: 若一個大的方法申明為synchronized將會影響效率
同步塊
- 同步塊: synchronized(Obj){ }
- Obj稱之為同步監視器
- Obj可以是任何物件, 但是推薦使用共享資源作為同步監視器
- 同步方法中無需指定同步監視器, 因為同步方法的同步監視器就是this, 就是這個物件本身, 或者是class[反射中講解]
- 同步監視器的執行程序
- 第一個執行緒訪問, 鎖定同步監視器, 執行其中代碼
- 第二個執行緒訪問, 發現同步監視器被鎖定, 無法訪問
- 第一個執行緒訪問完畢, 解鎖同步監視器
- 第二個執行緒訪問, 發現同步監視器沒有鎖, 然后鎖定并訪問
神奇的代碼例子1
只在方法上加了一個關鍵詞即可解決問題! 這個例子是不安全的買票, 給buy方法加了一個synchronized
package com.kuang.syn;
//不安全的買票
//執行緒不安全,有負數
public class UnsafeBuyTicket {
public static void main(String[] args) {
BuyTicket station = new BuyTicket();
new Thread(station,"苦逼的我").start();
new Thread(station,"牛逼的你們").start();
new Thread(station,"可惡的黃牛黨").start();
}
}
class BuyTicket implements Runnable{
//票
int tickerNums = 10;
boolean flag = true;//外部停止方式
@Override
public void run() {
//買票
while (flag){
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//synchronized同步方法, 鎖的是this
private synchronized void buy() throws InterruptedException {
//判斷是否有票
if(tickerNums<=0){
return;
}
//模擬延時
Thread.sleep(100);
//買票
System.out.println(Thread.currentThread().getName()+"拿到"+tickerNums--);
}
}
[看這完美的run]
苦逼的我拿到10
可惡的黃牛黨拿到9
可惡的黃牛黨拿到8
可惡的黃牛黨拿到7
可惡的黃牛黨拿到6
可惡的黃牛黨拿到5
可惡的黃牛黨拿到4
牛逼的你們拿到3
牛逼的你們拿到2
牛逼的你們拿到1
神奇的代碼例子2
鎖變化的量, 具體看代碼例子吧~
package com.kuang.syn;
//不安全的取錢
//兩個人去銀行取錢,賬戶
public class UnsafeBank {
public static void main(String[] args) {
//賬戶
Account account = new Account(100, "結婚基金");
Drawing you = new Drawing(account, 50, "你");
Drawing girlFriend = new Drawing(account, 100, "girlFriend");
you.start();
girlFriend.start();
}
}
//賬戶
class Account{
int money;//余額
String name; //卡名
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
//銀行:模擬取款
class Drawing extends Thread{
Account account;//賬戶
//取了多少錢
int drawingMoney;
//現在手里有多少錢
int nowMoney;
public Drawing(Account account, int drawingMoney, String name){
super(name);
this.account = account;
this.drawingMoney = drawingMoney;
}
//取錢
//synchronized默認鎖的是塊, 在這里鎖這個run方法不行
@Override
public void run() {
//判斷有沒有錢
synchronized (account) {
if (account.money - drawingMoney < 0) {
System.out.println("錢不夠, 取不了");
return;
}
//模擬延時
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//卡內余額
account.money = account.money - drawingMoney;
//手里的錢
nowMoney = nowMoney + drawingMoney;
System.out.println("余額為" + account.money);
System.out.println(this.getName() + "手里的錢" + nowMoney);
}
}
}
[run]
余額為50
你手里的錢50
錢不夠, 取不了
行程已結束,退出代碼0
[21CopyOnWriteArrayList]
JUC
我不知道這一章講了啥, 然后這個代碼, 好像也看不懂, 代碼先仍這了
package com.kuang.demo01;
import java.util.concurrent.CopyOnWriteArrayList;
//測驗JUC安全型別的集合
public class TestJUC {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
for (int i = 0; i < 10000; i++) {
new Thread(()->{
list.add(Thread.currentThread().getName());
}).start();
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
[22死鎖]
死鎖是啥呢
- 多個執行緒各自占有一些共享資源, 并且互相等待其他執行緒占有的資源才能運行, 而導致兩個或者多個執行緒都在等待對方釋放資源, 都停止執行的情形, 某一個同步塊同時擁有"兩個以上物件的鎖"時, 就可能發生"死鎖的問題".
- 就是兩個小朋友, 鐵柱和翠花, 鐵柱在玩自己的奧特曼玩具, 翠花在玩自己的小公主玩具, 忽然, 鐵柱想玩翠花的小公主玩具, 翠花想玩鐵柱的奧特曼玩具, 然后就麻煩了, 想玩又不想交換, 于是發生了爭執, 就僵持在那里, 直到有一方讓步
來看代碼的解釋
多個執行緒互相抱著物件需要的資源, 然后形成僵持
卡死鎖了呢
package com.kuang.demo01;
public class DeadLock {
public static void main(String[] args) {
Makeup g1 = new Makeup(0,"灰姑涼");
Makeup g2 = new Makeup(1,"白雪公主");
g1.start();
g2.start();
}
}
//口紅
class Lipstick{
}
//鏡子
class Mirror{
}
//化妝
class Makeup extends Thread {
//需要的資源只有一份, 用static來保證只有一份
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
int choice;//選擇
String girlName;//使用化妝品的人
Makeup(int choice, String girlName) {
this.choice = choice;
this.girlName = girlName;
}
@Override
public void run() {
//化妝
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeup() throws InterruptedException {
if (choice == 0) {
synchronized (lipstick) {//獲得口紅的鎖
System.out.println(this.girlName + "獲得口紅的鎖");
Thread.sleep(1000);
synchronized (mirror) {//一秒鐘后想獲得鏡子
System.out.println(this.girlName + "獲得鏡子的鎖");
}
}
} else {
synchronized (mirror) {//獲得鏡子的鎖
System.out.println(this.girlName + "獲得鏡子的鎖");
Thread.sleep(2000);
synchronized (lipstick) {//一秒鐘后想獲得口紅
System.out.println(this.girlName + "獲得口紅的鎖");
}
}
}
}
}
[run]
灰姑涼獲得口紅的鎖
白雪公主獲得鏡子的鎖
怎么辦呢?
解開死鎖啦
package com.kuang.demo01;
public class DeadLock {
public static void main(String[] args) {
Makeup g1 = new Makeup(0,"灰姑涼");
Makeup g2 = new Makeup(1,"白雪公主");
g1.start();
g2.start();
}
}
//口紅
class Lipstick{
}
//鏡子
class Mirror{
}
//化妝
class Makeup extends Thread {
//需要的資源只有一份, 用static來保證只有一份
static Lipstick lipstick = new Lipstick();
static Mirror mirror = new Mirror();
int choice;//選擇
String girlName;//使用化妝品的人
Makeup(int choice, String girlName) {
this.choice = choice;
this.girlName = girlName;
}
@Override
public void run() {
//化妝
try {
makeup();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void makeup() throws InterruptedException {
if (choice == 0) {
synchronized (lipstick) {//獲得口紅的鎖
System.out.println(this.girlName + "獲得口紅的鎖");
Thread.sleep(1000);
}
synchronized (mirror) {//一秒鐘后想獲得鏡子
System.out.println(this.girlName + "獲得鏡子的鎖");
}
} else {
synchronized (mirror) {//獲得鏡子的鎖
System.out.println(this.girlName + "獲得鏡子的鎖");
Thread.sleep(2000);
}
synchronized (lipstick) {//一秒鐘后想獲得口紅
System.out.println(this.girlName + "獲得口紅的鎖");
}
}
}
}
[run]
白雪公主獲得鏡子的鎖
灰姑涼獲得口紅的鎖
白雪公主獲得口紅的鎖
灰姑涼獲得鏡子的鎖
行程已結束,退出代碼0
死鎖避免方法
產生死鎖的四個必要條件:
- 互斥條件: 一個資源每次只能被一個行程使用
- 請求與保持條件: 一個行程因請求資源而阻塞時, 對已獲得的資源保持不變
- 不剝奪條件: 行程已經獲得的資源, 在未使用完之前, 不能強行剝奪
- 回圈等待條件: 若干行程之間形成一種頭尾相接的回圈等待資源關系
上面列出了死鎖的四個必要條件, 我們只要想辦法破解其中的任意一個或多個條件就可以避免死鎖發生
[23Lock鎖]
簡單介紹
- 從JDK5.0開始, Java提供了更強大的執行緒同步機制----通過顯式定義同步鎖物件來實作同步, 同步鎖使用Lock物件充當
- java.util.concurrent.locks.Lock介面是控制多個執行緒對共享資源進行訪問的工具, 鎖提供了對共享資源的獨占訪問, 每次只能有一個執行緒對Lock物件加鎖, 執行緒開始訪問共享資源之前應先獲得Lock物件
- ReentrantLock類實作了Lock, 它擁有與synchronized相同的并發性和記憶體語意, 在實作執行緒安全的控制中, 比較常用的是ReentrantLock, 可以顯示加鎖, 釋放鎖.
代碼例子
package com.kuang.demo01;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
public static void main(String[] args) {
TestLock2 testLock2 = new TestLock2();
new Thread(testLock2).start();
new Thread(testLock2).start();
new Thread(testLock2).start();
}
}
class TestLock2 implements Runnable{
int ticketNums=10;
//定義lock鎖
private ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
lock.lock();//加鎖
if(ticketNums>0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ticketNums--);
}else {
break;
}
}finally {
//解鎖
lock.unlock();
}
}
}
}
總結
class A{
private final ReentrantLock lock = new ReentrantLock();
public void m(){
lock.lock();
try{
//保證執行緒安全的代碼
}finall{
lock.unlock();
//如果同步代碼有例外,需要將unlock()寫入finally陳述句塊
}
}
}
synchronized與Lock的對比
- Lock是顯示鎖(手動開啟和關閉鎖, 別忘記關閉鎖), synchronized是隱式鎖, 出了作用域自動釋放
- Lock只有代碼塊鎖, synchronized有代碼塊鎖和方法鎖
- 使用Lock鎖, JVM將花費較少的時間來調度執行緒, 性能更好, 并且具有更好的擴展行(提供更多的子類)
- 優先使用順序:
- Lock > 同步代碼塊(已經進入了方法體, 分配了相應資源) > 同步方法(在方法體之外)
[24生產者消費者問題]
應用場景
- 假設倉庫中只能存放一件產品, 生產者將生產出來的產品放入倉庫, 消費者將倉庫中產品取走消費
- 如果倉庫中沒有產品, 則生產者將產品放入倉庫, 否則停止生產并等待, 直到倉庫中的產品被消費者取走為止
- 如果倉庫中放有產品, 則消費者可以將產品取走消費, 否則停止消費并等待, 直到倉庫中再次放入產品為止
執行緒通信-分析
這是一個執行緒同步問題, 生產者和消費者共享一個資源, 并且生產者和消費者之間互相依賴, 互為條件
- 對于生產者, 沒有生產產品之前, 要通知消費者等待, 而生產了產品之后, 又需要馬上通知消費者消費
- 對于消費者, 在消費之后, 要通知生產者已經結束消費, 需要生產新的產品以供消費
- 在生產者消費者問題中, 僅有synchronized是不夠的
- synchronized可阻止并發更新共一個共享資源, 實作了同步
- synchronized不能用來實作不同執行緒之間的訊息傳遞(通信)
幾個方法
| 方法名 | 作用 |
|---|---|
| wait() | 表示執行緒一直等待, 直到其他執行緒通知, 與sleep不同, 會釋放鎖 |
| wait(long timeout) | 指定等待的毫秒數 |
| notify() | 喚醒一個處于等待狀態的執行緒 |
| notifyAll() | 喚醒同一個物件上所有呼叫wait()方法的執行緒, 優先級別高的執行緒有限調度 |
注意: 均是Object類的方法, 都只能在同步方法或者同步代碼塊中使用, 否則會拋出例外lllegalMonitorStateException
怎嘛解決
解決方式1
并發協作模型"生產者/消費者模式"—>管程法
- 生產者: 負責生產資料的模塊(可能是方法, 物件, 執行緒, 行程)
- 消費者: 負責處理資料的模塊(可能是方法, 物件, 執行緒, 行程)
- 緩沖區:消費者不能直接使用生產者的資料, 他們之間有個"緩沖區"
- 生產者將生產好的資料放入緩沖區, 消費者從緩沖區拿走資料
解決方式2
并發協作模型"生產者/消費者模式"—>信號燈法
- 設定一個標志位(flag)來判斷
[25管程法]
package com.kuang.demo01;
public class TestPC {
public static void main(String[] args) {
SynContainer container = new SynContainer();
new Productor(container).start();
new Consumer(container).start();
}
}
//生產者
class Productor extends Thread{
SynContainer container;
public Productor(SynContainer container){
this.container = container;
}
//生產
@Override
public void run() {
for (int i = 0; i < 100; i++) {
container.push(new Chicken(i));
System.out.println("生產了"+i+"只雞");
}
}
}
//消費者
class Consumer extends Thread{
SynContainer container;
public Consumer (SynContainer container){
this.container = container;
}
//消費
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消費了-->"+container.pop().id+"只雞");
}
}
}
//產品
class Chicken{
int id;
public Chicken(int id){
this.id = id;
}
}
//緩沖區
class SynContainer{
//需要一個容器大小
Chicken[] chickens = new Chicken[10];
//容器計數器
int count = 0;
//生產者放入產品
public synchronized void push(Chicken chicken){
//如果容器滿了,就需要等待消費者
if(count==chickens.length){
//通知消費者消費,生產者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果沒有滿,我們就需要丟入產品
chickens[count]=chicken;
count++;
//可以通知消費者消費了
this.notifyAll();
}
//消費者消費產品
public synchronized Chicken pop(){
//判斷能否消費
if(count==0){
//等待生產者生產,消費者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果可以消費
count--;
Chicken chicken = chickens[count];
//吃完了,就通知生產者生產
this.notifyAll();
return chicken;//看一下吃的是哪只
}
}
[run]
生產了0只雞
生產了1只雞
生產了2只雞
生產了3只雞
生產了4只雞
生產了5只雞
生產了6只雞
生產了7只雞
生產了8只雞
生產了9只雞
生產了10只雞
消費了-->9只雞
消費了-->10只雞
生產了11只雞
消費了-->11只雞
生產了12只雞
消費了-->12只雞
生產了13只雞
消費了-->13只雞
生產了14只雞
消費了-->14只雞
消費了-->15只雞
生產了15只雞
消費了-->8只雞
生產了16只雞
消費了-->16只雞
生產了17只雞
消費了-->17只雞
生產了18只雞
消費了-->18只雞
生產了19只雞
消費了-->19只雞
生產了20只雞
消費了-->20只雞
生產了21只雞
消費了-->21只雞
生產了22只雞
消費了-->22只雞
生產了23只雞
消費了-->23只雞
生產了24只雞
生產了25只雞
生產了26只雞
消費了-->24只雞
消費了-->26只雞
消費了-->27只雞
消費了-->25只雞
消費了-->7只雞
生產了27只雞
生產了28只雞
生產了29只雞
生產了30只雞
生產了31只雞
消費了-->6只雞
消費了-->31只雞
消費了-->30只雞
消費了-->29只雞
消費了-->28只雞
消費了-->5只雞
消費了-->4只雞
消費了-->3只雞
消費了-->2只雞
消費了-->1只雞
消費了-->0只雞
生產了32只雞
生產了33只雞
生產了34只雞
生產了35只雞
生產了36只雞
生產了37只雞
生產了38只雞
生產了39只雞
生產了40只雞
生產了41只雞
消費了-->41只雞
消費了-->40只雞
生產了42只雞
消費了-->42只雞
生產了43只雞
消費了-->43只雞
消費了-->44只雞
消費了-->39只雞
消費了-->38只雞
消費了-->37只雞
生產了44只雞
消費了-->36只雞
生產了45只雞
消費了-->45只雞
生產了46只雞
消費了-->46只雞
生產了47只雞
消費了-->47只雞
生產了48只雞
消費了-->48只雞
生產了49只雞
消費了-->49只雞
生產了50只雞
消費了-->50只雞
生產了51只雞
消費了-->51只雞
消費了-->52只雞
消費了-->35只雞
消費了-->34只雞
消費了-->33只雞
生產了52只雞
消費了-->32只雞
生產了53只雞
生產了54只雞
生產了55只雞
生產了56只雞
生產了57只雞
生產了58只雞
生產了59只雞
生產了60只雞
生產了61只雞
生產了62只雞
生產了63只雞
消費了-->53只雞
消費了-->63只雞
消費了-->62只雞
消費了-->61只雞
消費了-->60只雞
消費了-->59只雞
消費了-->58只雞
消費了-->57只雞
消費了-->56只雞
消費了-->55只雞
消費了-->54只雞
生產了64只雞
生產了65只雞
生產了66只雞
生產了67只雞
生產了68只雞
生產了69只雞
生產了70只雞
生產了71只雞
生產了72只雞
生產了73只雞
消費了-->73只雞
消費了-->72只雞
消費了-->71只雞
消費了-->70只雞
消費了-->69只雞
消費了-->68只雞
消費了-->67只雞
消費了-->66只雞
消費了-->65只雞
消費了-->64只雞
生產了74只雞
生產了75只雞
生產了76只雞
生產了77只雞
生產了78只雞
生產了79只雞
生產了80只雞
生產了81只雞
生產了82只雞
生產了83只雞
消費了-->83只雞
消費了-->82只雞
消費了-->81只雞
消費了-->80只雞
消費了-->79只雞
消費了-->78只雞
消費了-->84只雞
消費了-->77只雞
消費了-->76只雞
消費了-->75只雞
消費了-->74只雞
生產了84只雞
生產了85只雞
生產了86只雞
生產了87只雞
生產了88只雞
生產了89只雞
生產了90只雞
生產了91只雞
生產了92只雞
生產了93只雞
生產了94只雞
生產了95只雞
消費了-->94只雞
消費了-->95只雞
消費了-->93只雞
消費了-->92只雞
消費了-->91只雞
消費了-->90只雞
消費了-->89只雞
消費了-->88只雞
消費了-->87只雞
消費了-->86只雞
消費了-->85只雞
生產了96只雞
生產了97只雞
生產了98只雞
生產了99只雞
消費了-->99只雞
消費了-->98只雞
消費了-->97只雞
消費了-->96只雞
行程已結束,退出代碼0
[26信號燈法]
package com.kuang.demo01;
public class TestPc2 {
public static void main(String[] args) {
TV tv = new TV();
new Player(tv).start();
new Watcher(tv).start();
}
}
//生產者--->演員
class Player extends Thread{
TV tv;
public Player(TV tv){
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(i%2==0){
this.tv.play("羅小黑戰記說好了就一定會更的周番播放中~");
}else{
this.tv.play("現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~");
}
}
}
}
//消費者-->觀眾
class Watcher extends Thread{
TV tv;
public Watcher(TV tv){
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
tv.watch();
}
}
}
//產品-->節目
class TV{
//演員表演,觀眾等待
//觀眾觀看,演員等待
String voice;//表演的節目
boolean flag = true;
//表演
public synchronized void play(String voice){
if (!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("演員表演了:"+voice);
//通知觀眾觀看
this.notifyAll();//通知喚醒
this.voice = voice;
this.flag = !this.flag;
}
//觀看
public synchronized void watch(){
if (flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("觀看了:"+voice);
//通知演員表演
this.notifyAll();
this.flag = !this.flag;
}
}
[run]
演員表演了:羅小黑戰記說好了就一定會更的周番播放中~
觀看了:羅小黑戰記說好了就一定會更的周番播放中~
演員表演了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
觀看了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
演員表演了:羅小黑戰記說好了就一定會更的周番播放中~
觀看了:羅小黑戰記說好了就一定會更的周番播放中~
演員表演了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
觀看了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
演員表演了:羅小黑戰記說好了就一定會更的周番播放中~
觀看了:羅小黑戰記說好了就一定會更的周番播放中~
演員表演了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
觀看了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
演員表演了:羅小黑戰記說好了就一定會更的周番播放中~
觀看了:羅小黑戰記說好了就一定會更的周番播放中~
演員表演了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
觀看了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
演員表演了:羅小黑戰記說好了就一定會更的周番播放中~
觀看了:羅小黑戰記說好了就一定會更的周番播放中~
演員表演了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
觀看了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
演員表演了:羅小黑戰記說好了就一定會更的周番播放中~
觀看了:羅小黑戰記說好了就一定會更的周番播放中~
演員表演了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
觀看了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
演員表演了:羅小黑戰記說好了就一定會更的周番播放中~
觀看了:羅小黑戰記說好了就一定會更的周番播放中~
演員表演了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
觀看了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
演員表演了:羅小黑戰記說好了就一定會更的周番播放中~
觀看了:羅小黑戰記說好了就一定會更的周番播放中~
演員表演了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
觀看了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
演員表演了:羅小黑戰記說好了就一定會更的周番播放中~
觀看了:羅小黑戰記說好了就一定會更的周番播放中~
演員表演了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
觀看了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
演員表演了:羅小黑戰記說好了就一定會更的周番播放中~
觀看了:羅小黑戰記說好了就一定會更的周番播放中~
演員表演了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
觀看了:現在是非常無聊的廣告時間~嘿嘿嘿~不想看廣告就換臺呀~哼唧~
行程已結束,退出代碼0
[27執行緒池]
使用執行緒池
- 背景: 經常創建和銷毀, 使用量特別大的資源, 比如并發情況下的執行緒, 對性能影響很大
- 思路: 提前創建好多個執行緒, 放入執行緒池中, 使用時直接獲取, 使用完畢放回池中, 可以避免頻繁創建銷毀, 實作重復利用, 類似生活中的公共交通工具
- 好處
- 提高相應速度(減少了創建新執行緒的時間
- 降低資源消耗(重復利用執行緒池中執行緒, 不需要每次都創建)
- 便于執行緒管理
- corePoolSize: 核心池的大小
- maxinumPoolSize: 最大執行緒數
- keepAliveTime: 執行緒沒有任務時最多保持多長時間后會停止
- JDK5.0起提供了執行緒池相關API: ExecutorSer和Executor
- ExecutorSer: 真正的執行緒池介面. 常見子類ThreadPoolExecutor
- void execute(Runnab command): 執行任務/命令, 沒有回傳值, 一般用來執行Runnab
- Futuresubmit(Callabletask): 執行任務, 有回傳值, 一般又來執行Callable
- void shutdown(): 關閉連接池
- Executor: 工具類, 執行緒池的工廠類, 用于創建并回傳不同型別的執行緒池
代碼
package com.kuang.demo01;
import java.util.concurrent.*;
public class TestPool {
public static void main(String[] args) {
//1.創建服務, 創建執行緒池
ExecutorService service = Executors.newFixedThreadPool(10);
//執行
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
service.execute(new MyThread());
//2.關閉鏈接
service.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
[run]好難啊,跟著敲完了,也不懂,555~
pool-1-thread-1
pool-1-thread-3
pool-1-thread-2
pool-1-thread-4
行程已結束,退出代碼0
[28總結]
總結也需要跟著寫代碼鴨
回顧總執行緒的創建
- 繼承Thread類
class MyThread1 extends Thread{
@Override
public void run() {
System.out.println("MyThread1");
}
}
- 實作Runnable介面
class MyThread2 implements Runnable{
@Override
public void run() {
System.out.println("MyThread2");
}
}
- 實作Callable介面
class MyThread3 implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("MyThread3");
return 100;
}
}
- 啟動上面三個執行緒
public class ThreadNew {
public static void main(String[] args) {
//MyThread1
new MyThread1().start();
//MyThread2
new Thread(new MyThread2()).start();
//MyThread3
FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());
new Thread(futureTask).start();
try {
Integer integer = futureTask.get();//獲取回傳值
System.out.println(integer);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
[run]
MyThread1
MyThread2
MyThread3
100
行程已結束,退出代碼0
回顧其他
這里什么也沒有~
狂神太強了, 秦疆就是我親哥! i了i了
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/259217.html
標籤:java
