1. 程式人生 > 其它 >多執行緒之死鎖、生產者與消費者模型以及執行緒池

多執行緒之死鎖、生產者與消費者模型以及執行緒池

死鎖產生的四個必要條件
  • 互斥條件:一個資源每次只能被一個程序使用

  • 請求與保持條件:一個程序因請求資源而阻塞時,對已獲得的資源保持不放

  • 不剝奪條件:程序已獲得的資源,在未使用完之前,不能強制剝奪

  • 迴圈等待條件:若干程序之間形成一種頭尾相接的迴圈等待資源關係

例項
package com.yeyue.thread;

public class DeadLock {
public static void main(String[] args) {
new Makeup(0,"灰姑涼").start();
new Makeup(1,"白雪公主").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(1000);
synchronized (lipstick) {
System.out.println(this.girlName + "獲得了口紅的鎖");
}
}
}
}
}
避免死鎖
package com.yeyue.thread;

public class DeadLock {
public static void main(String[] args) {
new Makeup(0,"灰姑涼").start();
new Makeup(1,"白雪公主").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(1000);
}
synchronized (lipstick) {
System.out.println(this.girlName + "獲得了口紅的鎖");
}
}
}
}
synchronized與lock的對比
  • lock是顯示鎖(手動開啟和關閉鎖,別忘記關鎖)synchronized是隱式鎖,除了作用域自動釋放

  • lock只有程式碼塊鎖,synchronized有程式碼塊鎖和方法鎖

  • 使用lock鎖,jvm將花費較少的時間來排程執行緒,效能更好。而且具有更好的擴充套件性(提供更多的子類)

  • 優先使用順序:

    lock>同步程式碼塊(已經進入方法體,分配了相應資源)>同步方法(在方法體之外)

    例項
    package com.yeyue.thread;

    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 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();
    }
    }
    }
    }
生產者消費者模型-->利用緩衝區解決:管程法
package com.yeyue.thread;

//測試:生產者消費者模型-->利用緩衝區解決:管程法

//生產者,消費者,產品,緩衝區
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+"只雞");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

//消費者
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+"只雞");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

//產品
class Chicken{
int id ; //產品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;
}












}
測試:生產者消費者模型2-->訊號燈法
package com.yeyue.thread;

//測試:生產者消費者模型2-->訊號燈法
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 {
//演員表演,觀眾等待 T
//觀眾觀看,演員等待 F
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;
}

}
執行緒池
package com.yeyue.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestPool {
public static void main(String[] args) {
//1、建立服務,建立執行緒池
//newFixedThreadPool 引數:執行緒池大小
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());
}
}