1. 线程阻塞
- 同步阻塞
- 调用sleep(),join()方法的时候,sleep()转为休眠,时间到自动唤醒
wait(),notify()方法配套,转为等待,同时释放资源,通过notify()方法唤醒
yield(),释放资源,与其他线程重新抢占资源,抢到就执行
- suspend()和resume(),由jdk1.0提供,jdk1.2之后就被放弃了,它也是让线程暂停,但是它不释放资源,导致死锁出现
2. 线程死锁
死锁产生的必要条件:
1>互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
2>不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
3>请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占用。
4>循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路
在我们的项目中,我们不希望看到死锁的发生,为了避免,以上四个条件,破坏其中任意一个,死锁就结束了
注意:过多的同步会导致死锁
死锁示例如下:
public class MyRun implements Runnable { private static Object a = new Object(); private static Object b = new Object(); private boolean flag = true; public void changeFlag() { flag = false; } @Override public void run() { if (flag) { synchronized (a) { System.out.println(Thread.currentThread().getName() + "锁定了资源a"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (b) { System.out.println(Thread.currentThread().getName() + "锁定资源b"); } } } else { synchronized (b) { System.out.println(Thread.currentThread().getName() + "锁定了资源b"); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (a) { System.out.println(Thread.currentThread().getName() + "锁定资源a"); } } } } }
测试如下:
public class Test { public static void main(String[] args) { MyRun mra = new MyRun(); new Thread(mra, "线程1").start(); MyRun mrb = new MyRun(); mrb.changeFlag(); new Thread(mrb, "线程2").start(); } }
3. Object对线程的支持
wait():让线程暂停执行,进入阻塞状态,要求必须有synchronized来修饰
notify():把阻塞的线程唤醒,这里唤醒的是针对wait()阻塞的线程,如果有多个阻塞的,只唤醒第一个
notifyAll():唤醒所有的
以上三个方法,都是针对同一个对象
wait()与sleep()的差别:
- wait是属于Object类提供的方法,通过wait休眠的线程,不会自动唤醒,需要依靠notify来唤醒
- sleep是线程类Thread提供的方法,休眠后到时间自动唤醒,不需要依靠其他方法
4.生产者消费者模式
生产者将产品交给店员(Clerk),而消费者从店员处取走产品,店员一次只能持有固定数量的产品,如果生产者生产了过多的产品,店员叫生产者等一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品
生产者生产的商品保存在仓库中:
public class Factory { private int num = 1;// 商品数量,默认为10个 /** * 商品入库 */ public synchronized void addProduct() { if (num >= 10) { // 这里不能继续生产了 System.out.println("仓库已满,不能再生产了"); try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } num++; System.out.println("生产者生产了一个商品,现在的商品库存为:" + num); this.notify(); } } /** * 商品出库 */ public synchronized void subProduct() { if (num <= 0) { // 没有商品了,所以不能继续消费了 System.out.println("商品没有了,不能继续消费了"); try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } num--; System.out.println("消费者消费了一个商品,现在的商品库存为:" + num); this.notify(); } } }
生产者生产了商品,就需要把商品存放到仓库中:
public class Productor implements Runnable { private Factory factory; public Productor(Factory factory) { this.factory = factory; } @Override public void run() { while (true) { factory.addProduct(); } } }
消费者要想实现消费,也需要从仓库中获取商品:
public class Customer implements Runnable { private Factory factory; public Customer(Factory factory) { this.factory = factory; } @Override public void run() { while (true) { factory.subProduct(); } } }
测试代码:
/** * 生产者消费者模式 * 生产者生产商品,消费者用来消费商品 * 每生产一个商品,商品的数量就应该加1,没消费一个商品,商品的数量就要减1 * 应该有一个地方用来保存商品,比如仓库 * 仓库用来保存商品,保存时,商品数量应该有上限(比如数量不能超过10个) * 当仓库的商品数量达到10个以后,不能再生产了 * 当商品数量为0以后,消费者就不能再消费了 * * * @author wendi * */ public class Test { public static void main(String[] args) { Factory factory = new Factory(); Productor p = new Productor(factory); Customer c = new Customer(factory); new Thread(p).start(); new Thread(c).start(); } }
运行结果:
生产者生产了一个商品,现在的商品库存为:2
生产者生产了一个商品,现在的商品库存为:3
生产者生产了一个商品,现在的商品库存为:4
生产者生产了一个商品,现在的商品库存为:5
生产者生产了一个商品,现在的商品库存为:6
生产者生产了一个商品,现在的商品库存为:7
生产者生产了一个商品,现在的商品库存为:8
消费者消费了一个商品,现在的商品库存为:7
生产者生产了一个商品,现在的商品库存为:8
消费者消费了一个商品,现在的商品库存为:7
消费者消费了一个商品,现在的商品库存为:6
消费者消费了一个商品,现在的商品库存为:5
消费者消费了一个商品,现在的商品库存为:4
消费者消费了一个商品,现在的商品库存为:3
消费者消费了一个商品,现在的商品库存为:2
生产者生产了一个商品,现在的商品库存为:3
生产者生产了一个商品,现在的商品库存为:4
生产者生产了一个商品,现在的商品库存为:5
生产者生产了一个商品,现在的商品库存为:6
生产者生产了一个商品,现在的商品库存为:7
生产者生产了一个商品,现在的商品库存为:8
生产者生产了一个商品,现在的商品库存为:9
生产者生产了一个商品,现在的商品库存为:10
仓库已满,不能再生产了
消费者消费了一个商品,现在的商品库存为:9
生产者生产了一个商品,现在的商品库存为:10
仓库已满,不能再生产了
消费者消费了一个商品,现在的商品库存为:9
消费者消费了一个商品,现在的商品库存为:8
消费者消费了一个商品,现在的商品库存为:7
消费者消费了一个商品,现在的商品库存为:6
消费者消费了一个商品,现在的商品库存为:5
消费者消费了一个商品,现在的商品库存为:4
消费者消费了一个商品,现在的商品库存为:3
生产者生产了一个商品,现在的商品库存为:4
生产者生产了一个商品,现在的商品库存为:5
生产者生产了一个商品,现在的商品库存为:6
消费者消费了一个商品,现在的商品库存为:5
生产者生产了一个商品,现在的商品库存为:6
生产者生产了一个商品,现在的商品库存为:7
生产者生产了一个商品,现在的商品库存为:8
生产者生产了一个商品,现在的商品库存为:9
生产者生产了一个商品,现在的商品库存为:10
消费者消费了一个商品,现在的商品库存为:9
消费者消费了一个商品,现在的商品库存为:8
消费者消费了一个商品,现在的商品库存为:7
消费者消费了一个商品,现在的商品库存为:6
消费者消费了一个商品,现在的商品库存为:5
消费者消费了一个商品,现在的商品库存为:4
消费者消费了一个商品,现在的商品库存为:3
消费者消费了一个商品,现在的商品库存为:2
消费者消费了一个商品,现在的商品库存为:1
消费者消费了一个商品,现在的商品库存为:0
商品没有了,不能继续消费了
生产者生产了一个商品,现在的商品库存为:1
生产者生产了一个商品,现在的商品库存为:2
生产者生产了一个商品,现在的商品库存为:3
生产者生产了一个商品,现在的商品库存为:4
消费者消费了一个商品,现在的商品库存为:3
消费者消费了一个商品,现在的商品库存为:2
消费者消费了一个商品,现在的商品库存为:1
消费者消费了一个商品,现在的商品库存为:0
生产者生产了一个商品,现在的商品库存为:1
消费者消费了一个商品,现在的商品库存为:0
。。。。。。