執行緒簡介
任務?
程式?
行程 Process?執行程式的一次執行程序,是一個動態的概念,是系統資源分配的單位
執行緒 Thread?一個行程中可以包含若干個執行緒,行程中至少有一個執行緒,執行緒是CPU調度和執行的單位
模擬多執行緒
執行緒實作(重點)
執行緒的創建
一、Thread類
1、使用方法
1.自定義執行緒類繼承Thread類
2.重寫run()方法,撰寫執行緒執行體
3.創建執行緒物件,呼叫start()方法啟動執行緒
2、代碼示例
//創建執行緒方式一:繼承Thread類,重寫run()方法,呼叫start()開啟執行緒
public class TestThread1 extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Thread----:"+i);
}
}
public static void main(String[] args) {
//main執行緒,主執行緒
//創建一個執行緒物件
TestThread1 testThread1=new TestThread1();
//呼叫方法開啟執行緒
testThread1.start();
for (int i = 0; i < 10; i++) {
System.out.println("Main--------:"+i);
}
}
}
3、運行結果
Main--------:0
Main--------:1
Thread----:0
Thread----:1
Main--------:2
Thread----:2
Main--------:3
Main--------:4
Main--------:5
Main--------:6
Thread----:3
Main--------:7
Main--------:8
Main--------:9
Thread----:4
Thread----:5
Thread----:6
Thread----:7
Thread----:8
Thread----:9
4、小結
執行緒開啟不一定立即執行,而是由CPU選擇調度執行
5、案例
下載圖片
//練習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 testThread2_1 = new TestThread2("https://img2.baidu.com/it/u=287632534,2172937882&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=309","CSGO1.jpg");
TestThread2 testThread2_2 = new TestThread2("https://img0.baidu.com/it/u=3909898413,2777003333&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800","CSGO2.jpg");
TestThread2 testThread2_3 = new TestThread2("https://img0.baidu.com/it/u=1130153521,1400899467&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800","CSGO3.jpg");
testThread2_1.start();
testThread2_2.start();
testThread2_3.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例外");
}
}
}
二、Runnable介面
1、使用方法
1.定義TestThread3類實作Runnable介面
2.實作run()方法,撰寫執行緒執行體
3.創建執行緒物件,傳入testThread3物件,呼叫start()方法啟動執行緒
代理方法
2、代碼示例
public class TestThread3 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("run:"+i);
}
}
public static void main(String[] args) {
TestThread3 testThread3=new TestThread3();
new Thread(testThread3).start();
for (int i = 0; i < 10; i++) {
System.out.println("main:"+i);
}
}
}
3、運行結果
main:0
run:0
main:1
run:1
main:2
run:2
main:3
run:3
main:4
run:4
main:5
run:5
main:6
run:6
main:7
run:7
main:8
run:8
main:9
run:9
4、對比
繼承Thread類
子類繼承Thread類具備多執行緒能力
通過子類物件.start() 啟動
不建議使用:避免OOP單繼承局限性
實作Runnable介面
實作介面Runnable具有多執行緒能力
傳入目標物件+Thread物件.start() 啟動 代理模式 一份資源多個代理
StartThread station=new StartThread();
new Thread(station,"小明").start();
new Thread(station,"小紅").start();
new Thread(station,"小剛").start();
建議使用:避免單繼承局限性,靈活方便,方便同一個物件被多個執行緒使用
5、初識并發問題
購買車票場景問題
代碼
//多個執行緒同時操作同一個物件
//買火車票的例子
public class TestThread4 implements Runnable{
private int ticketNums=10;
@Override
public void run() {
while (true){
if (ticketNums<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":拿到了第"+ticketNums--+"張票");
}
}
public static void main(String[] args) {
TestThread4 testThread4=new TestThread4();
new Thread(testThread4,"1號執行緒").start();
new Thread(testThread4,"2號執行緒").start();
new Thread(testThread4,"3號執行緒").start();
}
}
結果
1號執行緒:拿到了第10張票
3號執行緒:拿到了第9張票
2號執行緒:拿到了第8張票
2號執行緒:拿到了第6張票
3號執行緒:拿到了第7張票
1號執行緒:拿到了第6張票
1號執行緒:拿到了第5張票
2號執行緒:拿到了第5張票
3號執行緒:拿到了第4張票
3號執行緒:拿到了第3張票
2號執行緒:拿到了第1張票
1號執行緒:拿到了第2張票
車票重復購買:多個執行緒同時操作同一個資源的情況下,執行緒不安全,資料紊亂
龜兔賽跑問題
//模擬龜兔賽跑
public class Race implements Runnable{
private static String winner;
@Override
public void run() {
for (int i = 0; i <=100; i++) {
if (Thread.currentThread().getName()=="兔子"&&i%10==0){
try {
Thread.sleep(2 );
} 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;
}else {
if (steps==100){
winner=Thread.currentThread().getName();
System.out.println("winner is"+winner);
return true;
}
}
return false;
}
public static void main(String[] args) {
Race race=new Race();
new Thread(race,"兔子").start();
new Thread(race,"烏龜").start();
}
}
三、Callable介面(了解即可)
1、使用方法
1.實作Callable介面,需要回傳值型別
2.實作call方法,需要拋出例外
3.創建目標物件
4.創建執行服務:ExecutorService ser=Executors.newFixedThreadPool(1);
5.提交執行:Future
6.獲取結果:boolean r1=result1.get();
7.關閉服務:ser.shutdownNow();
2、代碼示例
public class TestCallable implements Callable<Boolean> {
//實作call方法,需要拋出例外
@Override
public Boolean call() throws Exception {
WebDownloader webDownloader = new WebDownloader();
webDownloader.downloader(url,name);
System.out.println("下載了檔案名為:"+name);
return true;
}
private String url;
private String name;
public TestCallable(String url, String name) {
this.url = url;
this.name = name;
}
public static void main(String[] args) {
//創建目標物件
TestCallable testThread2_1 = new TestCallable("https://img2.baidu.com/it/u=287632534,2172937882&fm=253&fmt=auto&app=138&f=JPEG?w=504&h=309","CSGO11.jpg");
TestCallable testThread2_2 = new TestCallable("https://img0.baidu.com/it/u=3909898413,2777003333&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800","CSGO21.jpg");
TestCallable testThread2_3 = new TestCallable("https://img0.baidu.com/it/u=1130153521,1400899467&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800","CSGO31.jpg");
//創建執行服務
ExecutorService ser= Executors.newFixedThreadPool(3);
//提交執行
Future<Boolean> submit1 = ser.submit(testThread2_1);
Future<Boolean> submit2 = ser.submit(testThread2_2);
Future<Boolean> submit3 = ser.submit(testThread2_3);
//獲取結果
try {
boolean rs1 = submit1.get();
boolean rs2 = submit2.get();
boolean rs3 = submit3.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
//關閉服務
ser.shutdownNow();
}
}
靜態代理模式
public class StacticProxy {
public static void main(String[] args) {
WeddingCompany weddingCompany=new WeddingCompany(new You());
weddingCompany.HappyMarry();
}
}
interface Marry{
void HappyMarry();
}
//真實角色
class You implements Marry{
@Override
public void HappyMarry() {
System.out.println("marry");
}
}
//代理角色
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 after() {
System.out.println("收尾款");
}
private void before() {
System.out.println("布置現場");
}
}
代理物件可以做很多真實物件做不了的事情,真實物件專注做自己的事情
Lambda運算式
函式式編程
為什么要使用Lambda運算式?避免匿名內部類過多,讓代碼看起來簡潔,去掉無意義的代碼只留下核心的邏輯
什么是函式式介面?任何介面只包含唯一一個抽象方法,則它就是一個函式式介面
public interface Runnable{
public abstract void run();
}
對于函式式介面,我們可以通過lambda運算式來創建該介面的物件
推導程序
//推導Lambda運算式
public class TestLambda1 {
//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 Lambda,匿名內部類");
}
};
like.lambda();
//6.用Lambda簡化
like=()->{
System.out.println("Lambda!!!");
};
like.lambda();
}
}
//1.定義一個介面
interface ILike{
void lambda();
}
//2.實作類
class Like implements ILike{
@Override
public void lambda() {
System.out.println("I Like Lambda");
}
}
執行緒狀態
一、五大狀態
執行緒有五大狀態:創建(new)、就緒(start)、阻塞(sleep、wait)、運行(執行)、死亡
創建:Thread t=new Thread(),執行緒物件一旦創建就進入到了新生狀態
就緒:創建后,呼叫start()方法,執行緒立即進入就緒狀態,但不意味著立即調度執行
阻塞:當呼叫sleep()、wait()或同步鎖定時,執行緒進入阻塞狀態,就是代碼不往下執行,阻塞事件解除后,重新進入就緒狀態,等待CPU調度執行
運行:進入運行狀態,執行緒才真正執行執行緒體的代碼塊
死亡:執行緒中斷或者結束,一旦進入死亡狀態,就不能再次啟動
- Thread.State 執行緒狀態
NEW: 尚未啟動的執行緒處于此狀態
RUNNABLE:在Java虛擬機中執行的執行緒處于此狀態
BLOCKED:被阻塞等待監視器鎖定的執行緒處于此狀態
WAITING:正在等待另一個執行緒執行特定動作的執行緒處于此狀態
TIMED_WAITING:正在等待另一個執行緒執行動作達到指定等待時間的執行緒處于此狀態
TERMINATED:已退出的執行緒處于此狀態
二、執行緒方法
//更改執行緒的優先級
setPriority(int newPriority)
//指定毫秒后讓執行緒休眠
static void sleep(long millis)
//等待該執行緒終止
void join()
//暫停正在執行的執行緒,運行其他的
static void yield()
//中斷執行緒(不要用這個方式)
void interrupt()
//測驗執行緒是否處于活動狀態
boolean isAlive()
1、執行緒停止
不推薦JDK提供的stop()、destroy()方法(已廢棄)
推薦讓執行緒自己停下來,建議使用一個標志位來終止執行緒
//測驗標志位flag
public class TestStop implements Runnable {
private boolean flag = true;
@Override
public void run() {
int i = 0;
while (flag==true) {
System.out.println("Thread is running..." + i);
i++;
}
}
public void stop() {
this.flag = false;
}
public static void main(String[] args) {
TestStop testStop = new TestStop();
new Thread(testStop).start();
System.out.println("Start");
for (int i = 0; i < 100000; i++) {
System.out.println("main is running..." + i);
if (i == 90000) {
testStop.stop();
break;
}
}
}
}
2、執行緒禮讓
作用是讓當前運行的執行緒暫停,但不阻塞,只是進入就緒狀態
讓CPU重新調度,有可能原本的行程再次運行進去,禮讓不一定成功
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()+" is running...");
Thread.yield();
System.out.println(Thread.currentThread().getName()+" is stop...");
}
}
案例有問題,不一定正確,實際可能與調度演算法有關
3、Join
Join合并執行緒,待此執行緒完成后,再執行其他執行緒,其他執行緒阻塞,類似”插隊“
public class TestJoin implements Runnable{
public static void main(String[] args) throws InterruptedException {
TestJoin testJoin=new TestJoin();
Thread thread = new Thread(testJoin);
thread.start();
for (int i = 0; i < 300; i++) {
if (i==200){
thread.join();
}
System.out.println("main..."+i);
}
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("vip..."+i);
}
}
}
4、執行緒狀態
- Thread.State 執行緒狀態
NEW: 尚未啟動的執行緒處于此狀態
RUNNABLE:在Java虛擬機中執行的執行緒處于此狀態
BLOCKED:被阻塞等待監視器鎖定的執行緒處于此狀態
WAITING:正在等待另一個執行緒執行特定動作的執行緒處于此狀態
TIMED_WAITING:正在等待另一個執行緒執行動作達到指定等待時間的執行緒處于此狀態
TERMINATED:已退出的執行緒處于此狀態
public class TestState {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for (int i = 0; i < 5; i++) {
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);
}
}
}
5、執行緒優先級
Java提供一個執行緒調度器來監控監視程式中啟動后進入到就緒狀態的所有執行緒,執行緒調度器按照優先級決定應該調度哪個執行緒來執行
-
執行緒的優先級用數字表示,范圍從1~10
-
通過getPriority().setPriority(int xxx)
public class TestPriority {
public static void main(String[] args) {
MyPriority myPriority = new MyPriority();
Thread thread1 = new Thread(myPriority,"thread1");
Thread thread2 = new Thread(myPriority,"thread2");
Thread thread3 = new Thread(myPriority,"thread3");
Thread thread4 = new Thread(myPriority,"thread4");
Thread thread5 = new Thread(myPriority,"thread5");
Thread thread6 = new Thread(myPriority,"thread6");
thread1.start();
thread2.setPriority(1);
thread2.start();
thread3.setPriority(4);
thread3.start();
thread4.setPriority(Thread.MAX_PRIORITY);
thread4.start();
thread5.setPriority(-1);
thread5.start();
thread6.setPriority(11);
thread6.start();
}
}
class MyPriority implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
}
}
優先級高的不一定先跑
6、守護(daemon)執行緒
- 執行緒分為用戶執行緒和守護執行緒
- 虛擬機必須確保用戶執行緒執行完畢
- 虛擬機不用等待守護執行緒執行完畢
- 例如:后臺記錄操作日志,監控記憶體,垃圾回收
//測驗守護執行緒
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);
thread.start();
new Thread(you).start();
}
}
//上帝
class God implements Runnable{
@Override
public void run() {
while(true){
System.out.println("god bless u");
}
}
}
//你
class You implements Runnable{
@Override
public void run() {
for (int i = 0; i < 365; i++) {
System.out.println("live...");
}
System.out.println("gg...");
}
}
執行緒同步(重點)
并發:多個執行緒操作同一個資源
排隊:多個執行緒訪問同一個物件,并且某些執行緒還想修改這個物件,這時我們就需要執行緒同步,執行緒同步其實是一種等待機制,多個需要同時訪問此物件的執行緒進入這個物件的等待池形成佇列,等待前面執行緒使用完畢,下一個執行緒再使用
由于同一個行程的多個執行緒共享一塊存盤空間,在帶來方便的同時,也帶來了訪問沖突問題,為了保證資料在方法中被訪問時的正確性,在訪問時加入鎖機制 synchronized,當一個執行緒獲得物件的排他鎖,獨占資源,其他執行緒必須等待,使用后釋放鎖即可,存在以下問題
- 一個執行緒持有鎖會導致其他所有需要此鎖的執行緒被掛起
- 在多執行緒競爭下,加鎖,釋放鎖會導致比較多的背景關系切換和調度延時,引起性能問題
- 如果一個優先級高的執行緒等待一個優先級低的執行緒釋放鎖,會導致優先級倒置,引起性能問題
購買車票場景問題2
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{
private int ticketNums=10;
boolean flag=true;
@Override
public void run() {
//買票
while (flag){
try {
buy();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void buy() throws InterruptedException {
if (ticketNums<=0){
flag=false;
return;
}
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+"拿到了"+ticketNums--);
}
public void stop() {
flag=false;
}
}
存在重復購票的情況,執行緒不安全
此時需要引入執行緒同步機制
同步方法
由于我們可以通過private關鍵字來保證資料物件只能被方法訪問,所以我們只需要對方法提出一套機制,這套機制就是synchronized關鍵字,它包括兩個用法:synchronized方法和synchronized塊
1.synchronized方法
public synchronized void method(int args){}
synchronized方法控制對“物件”的訪問,每個物件對應一把鎖,每個synchronized方法都必須獲得呼叫該方法的物件的鎖才能執行,否則執行緒會阻塞,方法一旦執行,就獨占該鎖,直到方法回傳才釋放鎖,后面被阻塞的執行緒才能獲得這個鎖,繼續執行
缺陷:若將一個大的方法宣告為synchronized將會影響效率
2.synchronized塊
同步塊
synchronized(互斥資源){}
Obj稱之為同步監視器
- Obj可以是任何物件,但是推薦使用共享資源作為同步監視器
- 同步方法中無需指定同步監視器,因為同步方法的同步監視器就是this,就是這個物件本身,或者是class
同步監視器的執行程序
1.第一個執行緒訪問,鎖定同步監視器,執行其中代碼
2.第二個執行緒訪問,發現同步監視器被鎖定,無法訪問
3.第一個執行緒訪問完畢,解鎖同步監視器
4.第二個執行緒訪問,發現同步監視器沒有鎖,然后鎖定并訪問
3.Lock鎖
可重用鎖(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();
}
}
public class TestLock2 implements Runnable{
int ticketNums=10;
private final 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();
}
}
}
}
synchronized與Lock的對比
- Lock是顯式鎖(手動開啟和關閉鎖,try開啟,finally關閉),synchronized是隱式鎖,出了作用域自動釋放
- Lock只有代碼塊鎖,synchronized有代碼塊鎖和方法鎖
- 使用Lock鎖,JVM將使用較少時間來調度執行緒,性能更好,并且具有更好的擴展性(提供更多子類)
- 優先使用順序:Lock->同步代碼塊(已經進入了方法體,分配了相應資源)->同步方法(在方法體外)
死鎖
多個執行緒各自占有一些共享資源,并且互相等待其他執行緒占用的資源才能運行,而導致兩個或者多個執行緒都在等待對方釋放資源,都停止執行的情景,某一個同步塊同時擁有“兩個以上物件的鎖”時,就可能發生“死鎖問題”
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 Lipstick lipstick=new Lipstick();
static Mirror mirror=new Mirror();
int choice;
String girlName;
public 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(500);
synchronized (mirror){
System.out.println(this.girlName+"獲得鏡子");
Thread.sleep(500);
}
}
}else {
synchronized (mirror){
System.out.println(this.girlName+"獲得鏡子");
Thread.sleep(500);
synchronized (lipstick){
System.out.println(this.girlName+"獲得口紅");
Thread.sleep(500);
}
}
}
}
}
產生死鎖的四個必要條件
1、互斥條件:一個資源每次只能被一個行程使用,
2、請求與保持條件:一個行程因請求資源而阻塞時,對已獲得的資源保持不放
3、不剝奪條件:行程已獲得的資源,在未使用完之前,不能強行剝奪
4、回圈等待條件:若干行程之間形成一種頭尾相接的回圈等待資源關系
只要破壞其中任意一個或多個就可以避免死鎖發生
執行緒通信問題
生產者消費者問題
- 倉庫中只能存放一件物品,生產者將生產出來的產品放入倉庫,消費者將倉庫中產品取走消費
- 如果倉庫中沒有產品,則生產者將產品放入倉庫,否則停止生產并等待,直到倉庫中的產品被消費者取走為止
- 如果倉庫中放有產品,則消費者可以將產品取走消費,否則停止消費并等待,直到倉庫再次放入產品為止
這是一個執行緒同步問題,生產者和消費者共享一個資源,并且生產者和消費者之間互相依賴,互為條件
關鍵方法wait()、notify()
wait:執行緒釋放鎖等待
notify:喚醒一個等待狀態的執行緒
管程法
public class TestPC {
public static void main(String[] args) {
SynContainer container =new SynContainer();
new Producer(container).start();
new Consumer(container).start();
}
}
class Producer extends Thread{
SynContainer container;
public Producer(SynContainer container) {
this.container = container;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
container.push(new Chicken(i));
} catch (InterruptedException e) {
e.printStackTrace();
}
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++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消費了"+i+"只雞");
try {
container.pop();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
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) throws InterruptedException {
if (chickens.length==count){
this.wait();
}
chickens[count]=chicken;
count++;
this.notifyAll();
}
public synchronized Chicken pop() throws InterruptedException {
if (count==0){
this.wait();
}
count--;
Chicken chicken = chickens[count];
this.notifyAll();
return chicken;
}
}
信號燈法
執行緒池
背景:經常創建和銷毀、使用量特別大的資源,比如并發情況下的執行緒,對性能影響很大
思路:提前創建好多個執行緒,放入執行緒池中,使用時直接獲取,使用完放回池中,可以避免頻繁創建銷毀,實作重復利用,類似生活中的公共交通工具
好處
1.提高回應速度(減少了創建新執行緒的時間)
2.降低資源消耗(重復利用執行緒池中執行緒,不需要每次都創建)
3.便于執行緒管理
? (1)corePoolSize:核心池大小
? (2)maximumPoolSize:最大執行緒數
? (3)keepAliveTime:執行緒沒有任務時最多保持多長時間后會終止
執行緒池相關API
ExecutorService和Executors
1.ExecutorService:真正的執行緒池介面,常見子類ThreadPoolExecutor
? (1)void execute(Runnable command):執行任務/命令,沒有回傳值,一般用來執行Runnable
? (2)
? (3)void shutdown():關閉執行緒池
2.Executors:工具類、執行緒池的工廠類,用于創建并回傳不同型別的執行緒池
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/501308.html
標籤:Java
上一篇:ObjectPostProcessor使用與多種用戶定義方式(9)
下一篇:@Autowired注解 --required a single bean, but 2 were found出現的原因以及解決方法
