多线程之死锁、生产者与消费者模型以及线程池
-
互斥条件:一个资源每次只能被一个进程使用
-
请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
-
不剥夺条件:进程已获得的资源,在未使用完之前,不能强制剥夺
-
实例
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()); } }