目录
线程的等待和通知
Object类中关于线程的方法
-
wait() 让当前线程进入等待状态,直到被通知为止
-
wait(long) 让当前线程进入等待状态,同时设置时间;直到被通知为止或时间结束
-
notify() 随机通知一个等待线程
-
notifyAll() 通知所有的等待线程
注意:等待和通知方法必须是锁对象,否则会抛出IllegalMonitorStateException
同步方法案例:
/**
* 通过锁对象将线程等待,经过5秒通知该线程来执行
*/
public class WaitDemo {
public synchronized void print() throws InterruptedException {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "--->" +i);
if(i == 50){
//让当前线程等待
this.wait();
}
}
}
public synchronized void notifyTest(){
//让等待的线程执行
this.notifyAll();
}
public static void main(String[] args) {
WaitDemo waitDemo = new WaitDemo();
new Thread(()->{
try {
waitDemo.print();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitDemo.notifyTest();
}
}
同步锁案例:
public class WaitDemo {
Lock lock=new ReentrantLock();
Condition condition=lock.newCondition();
public void print() throws InterruptedException {
lock.lock();
try {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+i);
if(i==50){
condition.await();
}
}
}finally {
lock.unlock();
}
}
public void lockTest(){
lock.lock();
try {
condition.signal();
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
WaitDemo waitDemo = new WaitDemo();
new Thread(()->{
try {
waitDemo.print();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitDemo.lockTest();
}
}
wait()和sleep()的区别
-
调用对象不同
wait() 由锁对象调用
sleep() 由线程调用
-
锁使用不同
执行wait后,自动释放锁
执行sleep后,不会释放锁
-
唤醒机制不同
执行wait后,可以被通知唤醒
执行sleep后,只能等待时间结束后,自动唤醒
生产者消费者模式
生产者消费者模式 是Controlnet网络中特有的一种传输数据的模式,设置方便,使用安全快捷。
一种设计模式,不属于GOF23
生产者和消费者
-
生产者
产生数据的模块就属于生产者
-
消费者
处理数据的模块就属于消费者
生产者和消费者之间的问题
-
耦合性高,生产者和消费者联系紧密,不利于系统的扩展和维护
-
并发性能低,同时能处理请求量少
-
忙闲不均,生产者和消费者的速度不一致,带来系统资源的浪费
实现过程:
-
通过添加缓冲区,设置上限
-
生产者生产数据,向缓冲区存放,如果满了,生产者进入等待,直到缓冲区有空的位置通知生产者生产;
-
消费者从缓冲区取数据进行消费,如果空了,消费者进入等待,直到缓冲区有数据再通知消费者消费
解决问题:
-
解耦
-
提高并发性能
-
解决忙闲不均
/**
* 包子铺
*/
public class BaoziShop {
/**
* 包子
*/
class Baozi{
private int id;
public Baozi(int id) {
this.id = id;
}
@Override
public String toString() {
return "包子--" + id;
}
}
//上限
public static final int MAX_COUNT = 100;
//缓冲区 存放数据
private List<Baozi> baozis = new ArrayList<>();
/**
* 做包子
*/
public synchronized void makeBaozi() throws InterruptedException {
//判断缓冲区是否满了
if(baozis.size() == MAX_COUNT){
System.out.printf("缓冲区满了,%s等待%n",Thread.currentThread().getName());
//让生产者线程等待
this.wait();
}else{
//通知生产者线程生产
this.notifyAll();
}
//创建包子
Baozi baozi = new Baozi(baozis.size() + 1);
System.out.println(Thread.currentThread().getName()+"做了"+baozi);
//保存到缓冲区
baozis.add(baozi);
}
/**
* 拿包子
*/
public synchronized void takeBaozi() throws InterruptedException {
//判断缓冲区是否空了
if(baozis.size() == 0){
System.out.printf("缓冲区空了,%s等待%n", Thread.currentThread().getName());
//让消费者等待
this.wait();
}else{
//通知消费者消费
this.notifyAll();
}
//获得第一个包子,并删除
if(baozis.size() > 0){
Baozi baozi = baozis.remove(0);
System.out.println(Thread.currentThread().getName()+"吃了"+baozi);
}
}
public static void main(String[] args) {
BaoziShop baoziShop = new BaoziShop();
//一个生产者
Thread productor = new Thread(() -> {
for (int i = 0; i < 100; i++) {
try {
baoziShop.makeBaozi();
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
productor.start();
//10个消费者吃10个包子
for (int i = 0; i < 10; i++) {
Thread consumer = new Thread(() ->{
try {
for (int j = 0; j < 10; j++) {
baoziShop.takeBaozi();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
consumer.start();
}
}
}
应用场景:
-
12306售票
-
消息队列
-
线程池
-
等等
阻塞队列
应用了生产者消费者模式的集合,能够根据数据满或空的情况,自动对线程执行等待和通知
BlockingQueue 接口
-
put 添加数据,达到上限会自动让线程等待
-
take 取并删除数据,数据空了会自动让线程等待
实现类
ArrayBlockingQueue 类 数据结构为数组
LinkedBlockingQueue类 链表结构
public class BaoziShop2 {
static class Baozi{
private int id;
public Baozi(int id){
this.id=id;
}
@Override
public String toString() {
return "包子---" +id;
}
}
public static void main(String[] args) {
BlockingQueue<Baozi> baozis = new ArrayBlockingQueue<Baozi>(100);
new Thread(()->{
for (int i = 0; i < 100; i++) {
try {
Baozi baozi = new Baozi(baozis.size() + 1);
baozis.put(baozi);
System.out.println(Thread.currentThread().getName()+"生产了"+baozi);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
for (int i = 0; i < 10; i++) {
new Thread(()->{
for (int j = 0; j < 20; j++) {
try {
Baozi take = baozis.take();
System.out.println(Thread.currentThread().getName()+"吃了"+take);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
}