目录
1.wait( )
使线程停止运行,会释放对象锁。
- 特点
- wait()使当前线程调用该方法后进行等待,并且将该线程置入锁对象的等待队列中,直到接到通知或被中断为止。
- wait()只能在同步方法 / 同步代码块中调用,如果调用wait()时,没有适当的锁,会抛出异常。
- wait()方法执行后,当前线程释放锁,其他线程可以竞争该锁。
- wait()之后的线程继续执行有两种方法:
- 调用该对象的notify()唤醒等待线程
- 线程等待是调用interrupt()中断该线程
/**
* wait()
* Author: qqy
*/
public class Test1 {
public static void main(String[] args) {
MyThread mt=new MyThread();
Thread thread=new Thread(mt);
thread.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
}
}
class MyThread implements Runnable{
private Object object=new Object();
@Override
public void run() {
synchronized (object){
System.out.println("wait()开始");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait()结束");
}
}
}
- wait(long time):如果到了预计时间还未被唤醒,线程将继续执行
/**
* wait(long time)
* Author: qqy
*/
public class Test1 {
public static void main(String[] args) {
MyThread mt=new MyThread();
Thread thread=new Thread(mt);
thread.start();
}
}
class MyThread implements Runnable{
private Object object=new Object();
@Override
public void run() {
synchronized (object){
System.out.println("wait()开始");
try {
//等1s后,结束
object.wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait()结束");
}
}
}
2.notify()
使停止的线程继续运行。
- 特点
- notify()必须在同步方法 / 同步代码块中调用,用来唤醒等待在该对象上的线程。如果有多个线程等待,则任意挑选一个线程唤醒。
- notify()执行后,唤醒线程不会立刻释放对象锁,等待唤醒线程全部执行完毕后才释放对象锁。
- notifyAll():唤醒所有在该对象上等待的线程。
/**
* notify()
* Author: qqy
*/
public class Test2 {
public static void main(String[] args) {
Object object=new Object();
MyThread1 myThread1=new MyThread1(object,true);
MyThread1 myThread2=new MyThread1(object,false);
Thread waitThread=new Thread(myThread1,"等待线程");
Thread notifyThread=new Thread(myThread2,"唤醒线程");
waitThread.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
notifyThread.start();
}
}
class MyThread1 implements Runnable{
//锁定对象
private Object object;
//决定等待or唤醒
private boolean flag;
public MyThread1(Object object, boolean flag) {
this.object = object;
this.flag = flag;
}
//等待方法
public void waitMethod(){
synchronized (object){
System.out.println(Thread.currentThread().getName()+" wait()开始");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" wait()结束");
}
}
//唤醒方法
public void notifyMethod(){
synchronized (object){
System.out.println(Thread.currentThread().getName()+" notify()开始");
object.notify();
System.out.println(Thread.currentThread().getName()+" notify()结束");
}
}
@Override
public void run() {
if(flag){
waitMethod();
}else {
notifyMethod();
}
}
}
3.线程阻塞的常见情况
- 调用sleep( ),主动放弃占有的cpu,不会释放对象锁
- 调用阻塞式 I/O 方法(read()、write()),在该方法返回前,线程阻塞
- 线程试图获取一个monitor,但该monitor被其他线程所持有导致阻塞
- 线程等待某个通知,即调用wait(),释放对象锁
- 调用线程suspend(),将线程挂起,容易导致死锁,已弃用。
4.monitor的两个队列
每一个monitor都有两个队列——同步队列、等待队列
-
同步队列:存放因为竞争monitor失败导致阻塞的线程,这些线程等待cpu调度再次竞争锁。
- 等待队列:存放因为调用wait()导致线程等待的线程,唤醒后进入同步队列竞争锁。
5.生产者与消费者模型
-
5.1 单生产、单消费
/**
* 生产者与消费者模型——单生产、单消费
* Author: qqy
*/
public class Test3 {
public static void main(String[] args) {
Goods1 goods1=new Goods1();
Thread produceThread=new Thread(new Producer1(goods1),"生产者");
Thread customThread=new Thread(new Customer1(goods1),"消费者");
produceThread.start();
customThread.start();
}
}
//商品类
class Goods1{
private String goodsName;
private int count;
//生产商品方法
public synchronized void set(String goodsName){
if(count>0){
System.out.println("库存充足,稍等一会儿");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.goodsName=goodsName;
this.count++;
System.out.println(Thread.currentThread().getName()+"生产"+toString());
notify();
}
//消费商品方法
public synchronized void get(){
if(count==0){
System.out.println("无商品,稍等片刻");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.count--;
System.out.println(Thread.currentThread().getName()+"消费"+toString());
notify();
}
//toString
@Override
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
", count=" + count +
'}';
}
}
//消费者线程
class Customer1 implements Runnable{
private Goods1 goods;
public Customer1(Goods1 goods) {
this.goods = goods;
}
@Override
public void run() {
goods.get();
}
}
//生产者线程
class Producer1 implements Runnable{
private Goods1 goods;
public Producer1(Goods1 goods) {
this.goods = goods;
}
@Override
public void run() {
goods.set("YSL");
}
}
-
5.2 多生产、多消费
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 生产者消费者模型——多生产、多消费
* Author: qqy
*/
public class Test {
public static void main(String[] args) {
Queue<Goods> goods=new LinkedList<>();
//标记商品
AtomicInteger name=new AtomicInteger(1);
Object monitor=new Object();
//两个生产者
Producer producer=new Producer(goods,monitor,name);
Producer producer1=new Producer(goods,monitor,name);
//两个消费者
Customer customer=new Customer(goods,monitor);
Customer customer1=new Customer(goods,monitor);
new Thread(producer,"生产者1").start();
new Thread(producer1,"生产者2").start();
new Thread(customer,"消费者1").start();
new Thread(customer1,"消费者2").start();
}
}
class Goods{
private String name;
public Goods(String name) {
this.name = name;
}
@Override
public String toString() {
return "Goods{" +
"name='" + name + '\'' +
'}';
}
}
//生产者
class Producer implements Runnable{
private final Queue<Goods> goods;
private final Object monitor;
private final AtomicInteger atomicInteger;
Producer(Queue<Goods> goods, Object monitor, AtomicInteger atomicInteger) {
this.goods = goods;
this.monitor = monitor;
this.atomicInteger = atomicInteger;
}
@Override
public void run() {
while(true) {
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (monitor) {
//商品池满了
if (this.goods.size() == 10) {
try {
//等待,直到通知没有商品了
this.monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
Goods goods=new Goods(String.valueOf(atomicInteger.getAndAdd(1)));
//将生产的商品加入队列
this.goods.add(goods);
//打印生产商品信息
System.out.println(Thread.currentThread().getName()+" 生产"+goods);
}
}
}
}
}
//消费者
class Customer implements Runnable{
private final Queue<Goods> goods;
private final Object monitor;
Customer(Queue<Goods> goods, Object monitor) {
this.goods = goods;
this.monitor = monitor;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (monitor){
//商品为空,通知所有生产者
if(this.goods.isEmpty()){
this.monitor.notifyAll();
}else{
//消费商品
Goods goods=this.goods.poll();
//打印消费信息
System.out.println(Thread.currentThread().getName()+" 消费"+goods);
}
}
}
}
}
-
sleep()与wait()的区别:
1. sleep()是Thread类中定义的方法,到了一定的时间后该线程自动唤醒,不会释放对象锁。
2. wait()是Object类中定义的方法,要想唤醒必须使用notify()、notifyAll()方法才能唤醒,会释放对象锁