六、线程的等待和唤醒

1.wait()和notify()的简单示范

public class Wait extends Thread{
public synchronized void run()
{
System.out.println(getName()+"执行notify()");
notify(); }
public static void main(String []args) {
Wait w = new Wait();
synchronized (w){
try {
w.start();
System.out.println(Thread.currentThread().getName() + "睡眠");
Thread.sleep(3000); System.out.println(Thread.currentThread().getName() + "等待");
w.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
}

程序结果:

main睡眠
main等待
Thread-0执行notify()

首先注意:wait()和notify()必须在synchronized代码块中。

这程序的流程是main线程先睡眠,然后被暂停,之后w线程执行notify()方法唤醒main(),如此就引出以下几个问题:

sleep()和wait()究竟有什么区别?

线程睡眠(sleep)不会放弃当前锁,而等待(wait)会。正如上面程序所示,即使线程睡眠的3000毫秒,但并没有放弃w的对象锁,所以run()方法不能获取w的对象锁,因此没有执行,体现在没有打印调用方法。而wait()执行后,main线程放弃对象锁,w线程获得自己的对象锁执行notify()方法,唤醒线程main,main继续执行。

w.wait()为什么是main线程暂停?

我们都知道sleep()是Thread类的静态方法,因此会睡眠执行该代码的线程。值得注意的是wait()虽然是Object()的实例方法,但是也具有sleep()类似的性质,即使运行代码的线程进入等待态。

notify()和notifyAll()的区别?

大部分人都耳熟能详,notify()唤醒监听器上一个线程,notifyAll()唤醒所有线程。notify()方法会随机唤醒一个线程,因此设计程序必须要合理。

wait()和wait(long mil)?

wait()需要notify()或者notifyAll()方法唤醒,而wait(long mil)同样,但是如果超过指定的时间还没有唤醒,那么自动唤醒。

这个程序其实是模仿博主如果天空不死的一个思路,而存在一个争论,即本程序中notify()方法删除,程序也会接着执行,原因位置,博主给出的解释是w线程结束后,释放的锁会由剩下的线程争抢,而该程序只剩下main线程,因此不必唤醒。显然有一点勉强,希望有大佬能解释。

2.wait()方法和notify()方法为何设置在Object类中?

wait()方法其实核心与sleep()不同就是放弃线程持有的对象锁,而notify()方法唤醒线程时只能在获取该对象锁的情况才有效(即唤醒线程和等待线程必须是同一把对象锁才能唤醒)。既然两者是通过对象锁联系到一起,那对象就有可能是几乎任何类的实例,因此将wait()、notify()和notifuAll()方法放在Object类中是合适的

3.一个简单的程序

我们通过wait()和notify()实现一个简单的功能,题目大致如下:

现有助理录不断入学生成绩,没录入一个学生,分析出总成绩和平均成绩

public class Grade {

    int g;
static double avg=0;
static int num=0;
boolean b=true;
public synchronized void input(int g)
{
if(!b) {
try {
// System.out.println("暂停"+Thread.currentThread().getName());
wait();
} catch (InterruptedException e) {
e.printStackTrace();
} }
this.g = g;
System.out.println("写入成绩"+g);
b=!b;
notify(); }
public synchronized void analyze()
{
if(b) {
try {
// System.out.println("暂停"+Thread.currentThread().getName());
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
double sum=(avg*num+g);
num++;
avg = sum / num;
System.out.println("Average of Grade is "+Grade.avg+", sum is "+sum);
b=!b;
notify(); }
public static void main(String []args)
{
Grade gr=new Grade();
C_Input c1=new C_Input(gr);
C_Analyze c2=new C_Analyze(gr);
c1.start();
c2.start();
} }
class C_Input extends Thread
{
Grade grade;
public C_Input (Grade g)
{
grade=g;
}
public void run()
{
for(int i=0;i<5;i++) {
int mg=(int)(Math.random()*100);
grade.input(mg);
}
} }
class C_Analyze extends Thread
{
Grade grade;
public C_Analyze (Grade g)
{
grade=g;
} public void run()
{
for(int i=0;i<5;i++) {
grade.analyze();
}
} }

结果:

写入成绩60
Average of Grade is 60.0, sum is 60.0
写入成绩84
Average of Grade is 72.0, sum is 144.0
写入成绩22
Average of Grade is 55.333333333333336, sum is 166.0
写入成绩96
Average of Grade is 65.5, sum is 262.0
写入成绩59
Average of Grade is 64.2, sum is 321.0

线程就先讲到这里,因为主要还是打基础,后面进阶我还会重新回来的!

最新文章

  1. HTML入门教程
  2. ubuntu服务管理
  3. WPF中实现验证码功能
  4. splay HYSBZ1588
  5. openssl知识点总结
  6. 十一、外观(Facade)模式--结构模式(Structural Pattern)
  7. 负载均衡探测器lbd
  8. 201621123027 Week02-Java基本语法与类库
  9. package.json文件解析
  10. 2522 和为K的倍数
  11. 解决Spark On Yarn yarn-cluster模式下的No Suitable Driver问题
  12. zabbix模板
  13. 多态(instanceof)
  14. spring+springmvc+ibatis整合注解方式实例【转】
  15. java 用PDFBox 删除 PDF文件中的某一页
  16. IDEA加载项目的设置是tomcat
  17. Docker入门 - 001 CentOS Docker 安装
  18. Go并发编程之美-CAS操作
  19. 将批量指定的docker镜像打成文件
  20. SRM464

热门文章

  1. 【并行计算-CUDA开发】CUDA线程、线程块、线程束、流多处理器、流处理器、网格概念的深入理解
  2. python3.6下pycharm连接mysql
  3. vue组件之间的通信, 父子组件通信,兄弟组件通信
  4. [转帖]国内拉取google kubernetes镜像
  5. [转帖]服务器备份工具:Amanda,Bakula,Clonezilla,Rsnapshot,Mondo Rescue
  6. [转帖]AARRR已是过去式,而RARRA才是更好的增长黑客模型
  7. SpringBoot起飞系列-数据访问(九)
  8. T100——r类 凭证报表 打印
  9. jdbc插入mysql时间差14个小时的解决方案
  10. aspose导出数据