關於同步與互斥
線程是進程的最小單元,同一進程中有多個線程
線程的交互有:互斥與同步
同步:因爲線程之間的合作,如有線程A將計算結果提供給線程B作進一步處理,那麼線程B在線程A將數據送達之前都將處於阻塞狀態。
互斥:系統中的多個線程必然要共享某種系統資源,如共享CPU,共享I/O設備,所謂間接相互制約即源於這種資源共享,打印機就是最好的例子,線程A在使用打印機時,其它線程都要等待,這就是互斥
線程A和線程B互斥訪問某個資源則它們之間就會產個順序問題——要麼線程A等待線程B操作完畢,要麼線程B等待線程操作完畢,這其實就是線程的同步了
同步包括互斥,互斥是一種特殊的同步
線程的方法
互斥的實現:synckronized(lockObj–創建的鎖對象)
lockObj.wait()方法是讓線程等待,後面需要用lockObj.notify()或者lockObj.notyfyAll()方法使線程喚醒,這兩個通常是成對出現的
如何理解同步 Wait Set(即線程等待區)
當一個線程獲得資源的時候,會有鎖,當線程獲得的資源不夠的時候,會調用wait()方法,釋放獲得的對象鎖,並進入Wait Set區,讓出資源來讓後續的線程獲取資源來做事,同第一個線程一樣,後續的線程也有可能會wait(),也跟着進入了Wait Set區,當後續的線程執行的差不多了,結束了,要調用notify()去喚醒之前在Wait Set裏的線程,或者notifyAll()喚醒所有線程重新搶佔資源
演示代碼如下:
線程同步經典問題重現:生產者與消費者模型
當生產者生產一個資源後,消費者消費一個資源,如果沒有資源,消費者等待生產者生產資源
//生產者和消費者模型
//設置公共資源
class PublicResource{
private int number=0;
//增加公共資源
//synchronize是關鍵字,同static用法,用在方法的前面,表示同步
public synchronized void increase(){
while(number!=0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number++;
System.out.println("生產1個資源,總資源爲:"+number);
notify();
}
//減少公共資源
public synchronized void decrease(){
while(number==0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
number--;
System.out.println("消耗1個資源,總資源爲:"+number);
notify();
}
}
//創建生產者線程,負責生產資源
class ProducerThread implements Runnable{
private PublicResource resource;
public ProducerThread(PublicResource resource) {
this.resource = resource;
}
@Override
public void run() {
for(int i=0;i<10;i++){
try {
//睡眠0~1秒的時間
Thread.sleep((long)(Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
resource.increase();
}
}
//創建消費者線程,負責生產資源
class UserThread implements Runnable{
private PublicResource resource;
public UserThread(PublicResource resource) {
this.resource = resource;
}
@Override
public void run() {
for(int i=0;i<10;i++){
try {
//睡眠0~1秒的時間
Thread.sleep((long)(Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
resource.decrease();;
}
}
//創建消費者
public class ProduceAndUse {
public static void main(String[] args) {
PublicResource resource = new PublicResource();
new Thread(new UserThread(resource)).start();
new Thread(new UserThread(resource)).start();
new Thread(new UserThread(resource)).start();
new Thread(new ProducerThread(resource)).start();
new Thread(new ProducerThread(resource)).start();
new Thread(new ProducerThread(resource)).start();
}
}
結果爲: