wait()与noyify()用于同步代码块或同步方法必须是内建锁
1. wait()—痴汉方法(运行态回阻塞态)
wait()就是使线程停止运行,会释放对象锁。
I.wait()方法会使当前线程调用该方法后进行等待,并且将该线程置入锁对象的等待队列中,直到接到通知或被中断为止。
II.wait()方法只能在同步方法或同步代码块中调用,如果调用wait()时没有适当的锁,会抛出异常。
III.wait()方法执行后,当前线程释放锁,其他线程可以竞争该锁。
wait()之后的线程继续执行有两种方法:
I.调用该对象的notify()方法唤醒等待线程。
II.线程等待时调用interrupt()中断该线程。
wait(long time):如果到了预计时间还未被唤醒,线程将继续执行。
class MyThread implements Runnable{
private Object object = new Object();
@Override
public void run() {
synchronized (object){
System.out.println("wait方法开始...");
try {
object.wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait方法结束...");
}
}
}
public class Test2{
public static void main(String[] args) throws Exception {
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread);
thread.start();
}
}
2.notify()
I.notify()方法也必须在同步方法或同步代码块中调用,用来唤醒等待在该对象上的线程。如果有多个线程等待,则任意挑选一个线程唤醒。
II.nitify()方法执行后,唤醒线程不会立即释放对象锁,要等待唤醒线程全部执行完毕后才释放对象锁。
例:唤醒线程全部执行完毕后才会释放对象锁
class MyThread implements Runnable{
//锁定对象
private Object object;
private boolean flag;
public MyThread(Object object,boolean flag) {
this.object = object;
this.flag = flag;
}
public void waitMethod(){
synchronized (object){
System.out.println("wait方法开始..."+Thread.currentThread().getName());
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait方法结束..."+Thread.currentThread().getName());
}
}
public void notifyMethod(){
synchronized (object){
System.out.println("notify方法开始..."+Thread.currentThread().getName());
//不会立即释放对象锁,要等notifyMethod方法执行完才会释放
object.notify();
System.out.println("notify方法结束..."+Thread.currentThread().getName());
}
}
@Override
public void run() {
if(flag){
this.waitMethod();
}else{
this.notifyMethod();
}
}
}
public class Test1{
public static void main(String[] args) {
Object object = new Object();
MyThread waitMethod = new MyThread(object,true);
MyThread notifyMethod = new MyThread(object,false);
Thread thread1 = new Thread(waitMethod,"等待线程");
Thread thread2 = new Thread(notifyMethod,"唤醒线程");
thread1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread2.start();
}
}
例:多个等待线程,则随意挑选一个唤醒
class MyThread implements Runnable{
//锁定对象
private Object object;
private boolean flag;
public MyThread(Object object,boolean flag) {
this.object = object;
this.flag = flag;
}
public void waitMethod(){
synchronized (object){
System.out.println("wait方法开始..."+Thread.currentThread().getName());
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait方法结束..."+Thread.currentThread().getName());
}
}
public void notifyMethod(){
synchronized (object){
System.out.println("notify方法开始..."+Thread.currentThread().getName());
object.notify();
System.out.println("notify方法结束..."+Thread.currentThread().getName());
}
}
@Override
public void run() {
if(flag){
this.waitMethod();
}else{
this.notifyMethod();
}
}
}
public class Test2{
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
MyThread waitMethod = new MyThread(object,true);
MyThread notifyMethod = new MyThread(object,false);
for(int i=0; i<5; i++){
Thread threadi = new Thread(waitMethod,"等待线程"+i);
threadi.start();
}
Thread.sleep(1000);
Thread thread = new Thread(notifyMethod,"唤醒线程");
thread.start();
}
}
3.notifyAll()
唤醒所有在该对象上等待的线程。
class MyThread implements Runnable{
//锁定对象
private Object object;
private boolean flag;
public MyThread(Object object,boolean flag) {
this.object = object;
this.flag = flag;
}
public void waitMethod(){
synchronized (object){
System.out.println("wait方法开始..."+Thread.currentThread().getName());
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait方法结束..."+Thread.currentThread().getName());
}
}
public void notifyMethod(){
synchronized (object){
System.out.println("notify方法开始..."+Thread.currentThread().getName());
object.notifyAll();
System.out.println("notify方法结束..."+Thread.currentThread().getName());
}
}
@Override
public void run() {
if(flag){
this.waitMethod();
}else{
this.notifyMethod();
}
}
}
public class Test1{
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
MyThread waitMethod = new MyThread(object,true);
MyThread notifyMethod = new MyThread(object,false);
for(int i=0; i<10; i++){
Thread threadi = new Thread(waitMethod,"等待线程"+i);
threadi.start();
}
Thread.sleep(1000);
Thread thread = new Thread(notifyMethod,"唤醒线程");
thread.start();
}
}
4.线程阻塞
1.调用sleep()方法,主动放弃占有的CPU,不会释放对象锁
2.调用阻塞式IO方法(read()、write()),在该方法返回前,线程阻塞。
3.线程试图获取一个monitor,但该monitor被其他线程所持有导致阻塞。
4.线程等待某个通知,即调用wait(),释放对象锁
5.调用线程suspend(),将线程挂起,容易导致死锁,已被废弃。
5.monitor的两个队列
每个monitor都有两个队列,一个称为同步队列,一个称为等待队列。
同步队列中存放了因为竞争monitor失败导致阻塞的线程,这些线程等待CPU调度再次竞争锁。
等待队列中存放因为调用wait()导致线程等待的线程,唤醒后进入同步队列竞争锁。
class Goods{
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;
count++;
System.out.println(Thread.currentThread().getName()+"生产"+goodsName+toString());
//唤醒等待消费的线程
notify();
}
//消费商品方法
public synchronized void get(){
if(count == 0){
System.out.println("商品已卖完~");
try {
//等待商品生产
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
System.out.println(Thread.currentThread().getName()+"消费"+goodsName+toString());
//唤醒生产者继续生产商品
notify();
}
@Override
public String toString() {
return " count = "+count;
}
}
class Consumer implements Runnable{
private Goods goods;
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
goods.get();
}
}
class Producer implements Runnable{
private Goods goods;
public Producer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
goods.set("一套口红");
}
}
public class Test2{
public static void main(String[] args) throws InterruptedException {
Goods goods = new Goods();
Thread thread1 = new Thread(new Producer(goods),"生产者");
Thread thread2 = new Thread(new Consumer(goods),"消费者");
thread2.start();
thread1.start();
}
}
例:多生产多消费:
class Goods{
private String goodsName;
private int count;
//生产商品方法
public synchronized void set(String goodsName){
while(count>0){
System.out.println("商品还有库存~");
try {
//等待消费者消费
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.goodsName = goodsName;
count++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"生产"+goodsName+toString());
//唤醒等待消费的线程
notifyAll();
}
//消费商品方法
public synchronized void get(){
//不断判断执行条件
while(count == 0){
System.out.println("商品已卖完~");
try {
//等待商品生产
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.count--;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"消费"+goodsName+toString());
//唤醒生产者继续生产商品
notifyAll();
}
@Override
public String toString() {
return " count = "+count;
}
}
class Consumer implements Runnable{
private Goods goods;
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while(true){
goods.get();
}
}
}
class Producer implements Runnable{
private Goods goods;
public Producer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while(true){
goods.set("一套口红");
}
}
}
public class Test2{
public static void main(String[] args) throws InterruptedException {
Goods goods = new Goods();
//存储多个生产、消费者线程
List<Thread> list = new ArrayList<>();
//10个消费者线程
for(int i=0; i<10; i++){
Thread thread = new Thread(new Consumer(goods),"消费者"+i);
list.add(thread);
}
//5个生产者线程
for(int i=0; i<5; i++){
Thread thread = new Thread(new Producer(goods),"生产者"+i);
list.add(thread);
}
for(Thread thread : list){
thread.start();
}
}
}
class Goods{
private String goodsName;
private int count;
public int getCount() {
return count;
}
//生产商品方法
public synchronized void set(String goodsName){
this.goodsName = goodsName;
count++;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"生产"+goodsName+toString());
//唤醒等待消费的线程
notifyAll();
}
//消费商品方法
public synchronized void get(){
//不断判断执行条件
while(count == 0){
System.out.println("商品已卖完~");
try {
//等待商品生产
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.count--;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"消费"+goodsName+toString());
//唤醒生产者继续生产商品
notifyAll();
}
@Override
public String toString() {
return " count = "+count;
}
}
class Consumer implements Runnable{
private Goods goods;
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while(true){
goods.get();
}
}
}
class Producer implements Runnable{
private Goods goods;
public Producer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while(this.goods.getCount() < 200){
goods.set("一套口红");
}
}
}
public class Test2{
public static void main(String[] args) throws InterruptedException {
Goods goods = new Goods();
//存储多个生产、消费者线程
List<Thread> list = new ArrayList<>();
//10个消费者线程
for(int i=0; i<10; i++){
Thread thread = new Thread(new Consumer(goods),"消费者"+i);
list.add(thread);
}
//5个生产者线程
for(int i=0; i<5; i++){
Thread thread = new Thread(new Producer(goods),"生产者"+i);
list.add(thread);
}
for(Thread thread : list){
thread.start();
}
}
}