多线程---wait()与notify()的学习
package com.mokuiran.thread.pcquestion;
//wait()的使用
public class WaitTest {
public static void main(String[] args) {
String text = "test"; //定义一个字符串作为锁对象
String anthor = "hello";
System.out.println("准备前。。。");
synchronized (text){
try {
System.out.println("同步代码块wait之前。。。");
// anthor.wait();//报错java.lang.IllegalMonitorStateException,因为锁对象调用
text.wait();//线程一直等待,锁对象被释放,直到被唤醒
System.out.println("同步代码块wait之后。。。");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("main后面的其余方法。。。");
}
}
package com.mokuiran.thread.pcquestion;
//wait()与notify()的使用1
public class WNTest {
public static void main(String[] args) {
String lock = "test"; //定义一个字符串作为锁的对象
Thread t1 = new Thread(new Runnable() {
package com.mokuiran.thread.pcquestion;
import java.util.ArrayList;
import java.util.List;
//wait()与notify()的使用2
public class WNTest2 {
public static void main(String[] args) {
//定义一个List存储String数据
List<String> list = new ArrayList<>();
//定义第一个线程,当list集合中元素数量不等于5时线程等待
Thread t1 = new Thread(new Runnable() {
Interrupt()方法会中断wait()
当线程处于wait()等待状态时,调用线程对象的interrupt()方法会中断线程的等待状态,会产生异常
package com.mokuiran.thread.pcquestion;
//测试interrupt()方法
public class InterruptTest {
public static void main(String[] args) {
SubThread t = new SubThread();
t.start();
try {
Thread.sleep(1000); //主线程睡眠2秒,确保子线程处于Wait等待状态
t.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static final Object Lock = new Object();//定义常量作为锁对象
static class SubThread extends Thread{
wait(long)方法
package com.mokuiran.thread.demo;
//测试notify()方法以及wait(long)方法
//wait(long)带有long类型参数的wait()等待,如果在参数指定的时间内没有被唤醒,超时后会自动唤醒
public class Test{
public static void main(String[] args) throws InterruptedException {
Object lock = new Object(); //定义一个对象作为子线程的锁对象
SubThread t1 = new SubThread(lock);
SubThread t2 = new SubThread(lock);
SubThread t3 = new SubThread(lock);
new Thread(t1,"1").start();
new Thread(t2,"2").start();
new Thread(t3,"3").start();
Thread.sleep(1000);
synchronized (lock){
// lock.notify();
/*只能随机唤醒其中一个线程,其他等待的线程依然处于等待状态,对于处于等待状态的线程来说,
错过了通知信号,这种现象也成为信号丢失*/
lock.notifyAll(); //唤醒所有线程
}
}
public static class SubThread extends Thread{
private Object lock; //定义实际变量作为锁的对象
public SubThread(Object lock) {
this.lock = lock;
}
通知过早的情况
package com.mokuiran.thread.demo;
public class Test {
static boolean flag = true;
public static void main(String[] args) {
Object lock = new Object();
Thread t1 = new Thread(new Runnable() {
wait条件发生了变化
package com.mokuiran.thread.demo;
import java.util.ArrayList;
import java.util.List;
public class Test{
public static void main(String[] args) {
//定义添加数据的线程对象
ThreadAdd threadAdd = new ThreadAdd();
//定义取数据的线程对象
ThreadSubtract threadSubtract = new ThreadSubtract();
threadSubtract.setName("sub1-->");
//测试一:先开启添加数据线程,再开启取数据线程,大多数情况下都会正常取数据
// threadAdd.start();
// threadSubtract.start();
//测试二:先开启取数据的线程,再开启添加数据的线程,取数据的线程会先等待,等到添加数据之后,再取数据
// threadSubtract.start();
// threadAdd.start();
//测试三:开启两个取数据的线程,再开启添加数据的线程
ThreadSubtract threadSubtract2 = new ThreadSubtract();
threadSubtract2.setName("sub2-->");
threadSubtract.start();
threadSubtract2.start();
threadAdd.start();
/*
第三次测试的某一次结果如下:
sub1--> begin wait...
sub2-->从集合中取了data后,集合中数据的数量:0
sub1--> end wait...
Exception in thread "sub1-->" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
分析可能的执行顺序:
threadSubtract线程先启动,取数据时,集合中没有数据,wait()等待
threadAdd线程获得CPU执行权,添加数据,把threadSubtract线程唤醒
threadSubtract2线程开启后获得CPU执行权,正常取数据
threadSubtract线程获得CPU执行权,打印end wait。。。,然后再执行list.remove(0)取数据时,现再
list集合中已经没有数据了,这时产生java.lang.IndexOutOfBoundsException异常
出现异常的原因:向list集合中添加了一个数据,却remove了两次
如何解决?
答:将判断条件中的if改为while
*/
}
//1.定义List集合
static List list = new ArrayList<>();
//2.定义方法从集合中取数据
public static void subtract(){
synchronized (list){
// if (list.size() == 0){
while (list.size() == 0){
try {
System.out.println(Thread.currentThread().getName()+" begin wait...");
list.wait();
System.out.println(Thread.currentThread().getName()+" end wait...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Object data = list.remove(0); //从集合中取(移除)一个数据
System.out.println(Thread.currentThread().getName()+"从集合中取了"+data+"后,集合中数据的数量:"+list.size());
}
}
//3.定义方法向集合中添加数据后,通知等待的线程取数据
public static void addtest(){
synchronized (list){
list.add("data");
list.notifyAll();
}
}
//4.定义线程类共调用add()取数据的方法
static class