本文主要内容:
(1)線程安全問題
(2)synchronized關鍵字
(3)join方法
(4)sleep方法與wait方法的差別
1.解決線程安全問題
讓倉庫對象被線程通路的時候,倉庫對象被鎖定,倉庫對象隻能被一個線程通路,其他線程處于等待狀态。
public class House {
private ArrayList<String> list = new ArrayList<>();
//向集合中添加元素的方法
public synchronized void add(){
if(list.size()<20){
list.add("a");
}else {
try {
this.notifyAll();
this.wait();//倉庫調用wait(),不是倉庫對象等待,而是調用倉庫生産者線程進入等待狀态
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//從集合中取元素
public synchronized void get(){
if(list.size()>0){
list.remove(0);
}else {
try {
this.notifyAll();
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//Producer、Customer、TestMain類和上述一樣
//運作不會産生異常,線程安全
2.特征修飾符:synchronized
同步的,一個時間點隻有一個線程通路
(2-1)将synchronized關鍵字放在方法的結構上
public synchronized void get(){
//鎖定的是調用方法時的那個對象
}
(2-2)将synchronized關鍵字放在方法(構造方法、塊)的内部
public void get(){
synchronized(對象){
......
}
}
3.通過上述的生産消費者模型總結
(1)利用線程安全鎖,特征修飾符synchronized,兩種不同的寫法,鎖定的是對象
(2)利用方法控制線程狀态來回切換方法如下:
wait(),notify(),notifyAll(),這些方法都是Object類中的方法
(3)Thread類中的方法
sleep(),setPriority();getPriority(),設定或擷取線程的優先級,數字越高優先級越高,更加容易擷取CPU配置設定的資源碎片
4.筆試題
(1)線程的幾種狀态

(2)sleep與wait方法的差別
sleep():它是Thread類中的靜态方法,可以直接用類調用,需要用對象調用方法,喚醒不需要别人,不會釋放鎖
wait():他是Object類的方法,需要用對象來調用方法,通路對象的其他線程等待,需要其他對象調用notify喚醒,等待後會釋放鎖
5.比較重要的方法(Thead類中的join方法)
(1)設計一個模型,有兩個線程,将two線程加入one裡面
(2)設計模型時,two線程在one的run裡面建立,保證兩個有先後順序
(3)two.join
public class ThreadOne extends Thread{
public void run(){
System.out.println("thread one start");
ThreadTwo two = new ThreadTwo();
two.start();
try {
two.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread one end");
}
}
public class ThreadTwo extends Thread {
public void run(){
System.out.println("thread two start");
System.out.println("thraed two end");
}
}
public class Test {
public static void main(String[] args) {
ThreadOne one = new ThreadOne();
one.start();
}
}
//運作結果
thread one start
thread two start
thraed two end
thread one end
(4)在寫一個如下模型,在建立一個ThreadThree,one開始啟動(啟動後睡眠5000s),two考試啟動(加入到one中2000s),three開始啟動(啟動後睡眠10000s),two開始加入到one中,2000s後one想将two從自己的線程中删除,但是two對象又被three對象鎖定了(10000s),所有one隻能等待three将two對象釋放後,才能踢掉。
public class ThreadOne extends Thread{
public void run(){
System.out.println("thread one start");
ThreadTwo two = new ThreadTwo();
two.start();
try {
two.join(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread one end");
}
}
public class ThreadTwo extends Thread {
public void run(){
System.out.println("thread two start");
ThreadThree three = new ThreadThree(this);
three.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread two end");
}
}
public class ThreadThree extends Thread{
private ThreadTwo two;
public ThreadThree(ThreadTwo two){
this.two = two;
}
public void run(){
System.out.println("thread three start");
synchronized (two){
System.out.println("two is locked");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("two is free");
}
System.out.println("thread three end");
}
}
public class Test {
public static void main(String[] args) {
ThreadOne one = new ThreadOne();
ThreadTwo two = new ThreadTwo();
ThreadThree three = new ThreadThree(two);
one.start();
}
}
//運作結果
thread one start
thread two start
thread three start
two is locked
thread two end
two is free
thread three end
thread one end