一、死鎖
1.概述
- 死鎖 : 死鎖是指兩個或兩個以上的進(jìn)程在執(zhí)行過程中,由于競爭資源或者由于彼此通信而造成的一種阻塞的現(xiàn)象,若無外力作用,它們都將無法往下執(zhí)行。
- 此時稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠(yuǎn)在互相等待的進(jìn)程稱為死鎖進(jìn)程
- 原理 :
-
- 某個線程執(zhí)行完成,需要先后嵌套鎖定兩個對象,在這個過程中,先鎖定了第一個對象
- 另一個線程執(zhí)行完成也需要先后嵌套鎖定兩個對象,在這個過程中,先鎖定了第二個對象
- 第一個線程執(zhí)行中,要執(zhí)行到第二個對象的時候,發(fā)現(xiàn)第二個對象被鎖定,進(jìn)入等待狀態(tài),等待交出鎖
- 第二個線程執(zhí)行中,要執(zhí)行到第一個對象的時候,發(fā)現(xiàn)第一個對象也被鎖定,也進(jìn)入等待狀態(tài)
- 此時兩個線程都在等待對方交出鎖,導(dǎo)致死鎖
2.代碼實現(xiàn)
public class Thread_01_DeadLock {public static void main(String[] args) {Object o1=new Object();Object o2=new Object();Thread t1=new Thread(new T1(o1, o2));Thread t2=new Thread(new T2(o1, o2));t1.start();t2.start();}
}
class T1 implements Runnable{Object o1;Object o2;public T1(Object o1,Object o2){this.o1=o1;this.o2=o2;}@Overridepublic void run() {synchronized (o1) {
System.out.println(Thread.currentThread().getName()+"-->T1o1已鎖定");synchronized (o2) {System.out.println(Thread.currentThread().getName()+"-->T1o2已鎖定");}}System.out.println("t1執(zhí)行完成");}
}
class T2 implements Runnable{Object o1;Object o2;public T2(Object o1,Object o2){this.o1=o1;this.o2=o2;}@Overridepublic void run() {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (o2) {System.out.println(Thread.currentThread().getName()+"-->T2o2已鎖定");synchronized (o1) {System.out.println(Thread.currentThread().getName()+"-->T2o1已鎖定");}}System.out.println("t2執(zhí)行完成");}
}
二、線程通信
1.概述
- Object中的方法
- wait : 讓當(dāng)前線程進(jìn)入等待狀態(tài)(掛起),并釋放鎖,當(dāng)被喚醒之后,接著掛起的位置繼續(xù)執(zhí)行,假如之前執(zhí)行了1、2,到3掛起,那么被喚醒后接著執(zhí)行3
- notify : 喚醒一個在該對象中掛起的任意一個線程
- notifyAll : 喚醒在該對象中掛起的所有線程
- 這幾個方法必須出現(xiàn)在加鎖的成員方法中
- wait : 如果是無參,則不會自動醒,也可以傳入long類型的值,代表毫秒數(shù),多久之后自動醒
- wait 和 sleep的區(qū)別 :
-
- sleep : 讓當(dāng)前線程進(jìn)入睡眠狀態(tài), 是靜態(tài)方法,和是否加鎖沒有關(guān)系,如果在加鎖的方法中,也不會釋放鎖
- wait : 讓當(dāng)前線程進(jìn)入掛起等待狀態(tài),必須在加鎖的成員方法中,另外會釋放鎖
2.使用方式
public class Thread_03_Wait {public static void main(String[] args) throws InterruptedException {Num num=new Num();Thread t1=new PrintNum(num);Thread t2=new PrintNum(num);t1.start();Thread.sleep(10);t2.start();}
}
class PrintNum extends Thread{Num num;public PrintNum(Num num){this.num=num;}@Overridepublic void run() {while (true) {num.printNums();}}
}
class Num{private int count =1;public synchronized void printNums(){System.out.println(Thread.currentThread().getName()+"-->"+count);count++;this.notifyAll();try {Thread.sleep(1000);this.wait();} catch (InterruptedException e) {e.printStackTrace();}}
}
3.生產(chǎn)者消費者

3.1.示例
public class Thread_04_Producer {public static void main(String[] args) {SynStack ss=new SynStack();Thread producer1=new Thread(new Producer(ss));Thread producer2=new Thread(new Producer(ss));Thread consumer1=new Thread(new Consumer(ss));Thread consumer2=new Thread(new Consumer(ss));producer1.start();producer2.start();consumer1.start();consumer2.start();}
}
class Producer implements Runnable{private SynStack ss;public Producer(SynStack ss){this.ss=ss;}@Overridepublic void run() {for (int i = 0; i < 26; i++) {ss.push((char)('a'+i));}}
}
class Consumer implements Runnable{private SynStack ss;public Consumer(SynStack ss){this.ss=ss;}@Overridepublic void run() {for (int i = 0; i < 26; i++) {ss.pop();try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}
}
class SynStack{int count=0;char[] data=new char[6];public synchronized void push(char ch){while(count ==data.length){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}if (count==0) {this.notifyAll();}data[count++]=ch;System.out.println(Thread.currentThread().getName()+"生產(chǎn)了 "+ch+" 還剩 "+count+" 個貨物");}public synchronized char pop(){while(count ==0){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}if (count==data.length) {this.notifyAll();}char ch=data[--count];System.out.println(Thread.currentThread().getName()+"消費了 "+ch+" 還剩 "+count+" 個貨物");return ch;}
}
三、單例模式
public class SingLeton {private SingLeton(){}private volatile static SingLeton singLeton;public static SingLeton getInstance(){if (singLeton==null) {synchronized (SingLeton.class) {if (singLeton==null) {singLeton=new SingLeton();} }}return singLeton;}
}
四、線程池
- 線程池的作用:
-
- 線程池作用就是限制系統(tǒng)中執(zhí)行線程的數(shù)量。
- 根據(jù)系統(tǒng)的環(huán)境情況,可以自動或手動設(shè)置線程數(shù)量,達(dá)到運行的最佳效果;
- 少了浪費了系統(tǒng)資源,多了造成系統(tǒng)擁擠效率不高。
- 用線程池控制線程數(shù)量,其他線程排隊等候。
- 一個任務(wù)執(zhí)行完畢,再從隊列的中取最前面的任務(wù)開始執(zhí)行。
- 若隊列中沒有等待進(jìn)程,線程池的這一資源處于等待。
- 當(dāng)一個新任務(wù)需要運行時,如果線程池中有等待的工作線程,就可以開始運行了,否則進(jìn)入等待隊列。
- 為什么要用線程池:
-
- 減少了創(chuàng)建和銷毀線程的次數(shù),每個工作線程都可以被重復(fù)利用,可執(zhí)行多個任務(wù)。
- 可以根據(jù)系統(tǒng)的承受能力,調(diào)整線程池中工作線線程的數(shù)目,防止因為消耗過多的內(nèi)存,而把服務(wù)器累趴下(每個線程需要大約1MB內(nèi)存,線程開的越多,消耗的內(nèi)存也就越大,最后死機)