关于线程 thread (4)线程的交互

线程交互的基础知识

首先要从java.lang.object的类的三个方法学习
void notify():唤醒此对象监视器上等待的单个线程
void notifyAll(): 唤醒此监视器上等待的所有线程。
void wait():导致当前的线程阻塞等,线程要立马放弃同步代码块被同步对象的锁(目前感觉不合理,可能错了),直到其他线程调用此对象的notify() 或者 notifyAll(). 并且wait的调用对象也得是被锁住的那个对象。(这个是后来发现的规则)

另外 wait还有两个很重要的重载方法:
void wait(long timeout) :导致当前的线程等待,直到其他线程调用此线程此对象的notify()方法或者notifyAll()方法,或者超过指定的时间量。
void wait(long timeout, int nanos): 导致当前的线程等待直到其他线程调用此对象的notify() 或者 notifyAll() 方法,或者超过某个实际时间量,或者其他线程中断当前线程。

线程不能在平常的情况下调用对象上等待或者通知的方法,除非这个线程持有该对象的锁。所以 wait , notify, notifyAll 只能在同步环境中用!

wait, notify, notifyall 都是object 的实例方法。正如每个对象的锁一样,每个对象也有一个线程列表,他们等待来自该信号通知。线程通过执行对象上的wait方法获得这个等待列表,从那时起,他就不再执行任何其他指令,直到调用对象的notify方法为止。如果多个线程在同一对象上等待,则只选择一个线程继续执行。如果没有线程等待,则不采取任何特殊操作。调用它的对象一定要一致。

注意哈,wait 和 notify 搭配使用的话,一定要搞清锁住的对象。

你可以模拟出以下场景,有几个线程给你要数据,但是你这个数据很重要,坚决不允许并发篡改的问题出现,那么你:
改数据可以!!一个一个来!! 于是乎在重点的地方乖乖上了把锁。
然后线程们一个接着一个访问!
但是忽然你发现,数据改着改着,到达了某种临界状态,不能再改啦!除非将数据调整到临界点以下。
那么你只能这样做!
线程1 过来要数据,,你大声的告诉他,数据没了,你等着!我做下处理。处理完你可以从中断处继续执行。
但是你是因为自己的数据不符合他的要求而给他说这些情况的,不代表你当前的数据不符合所有线程要求的条件,,万一在逻辑外等待的某线程,人家要求的数据是你现在正好可以提供的呢??所以你还得想个办法,让别的线程能进来,能给数据就给,不能给数据,就告诉后面来的线程让他们等着!
你忽然想到,线程1还拿着锁呢,这要是歇了还不把锁给你,别的线程永远进不来了。不靠谱。于是你又对他说了句,兄嘚,把你的锁给我。好让后面排队的人进来。
于是线程1把锁归还了,,后面在等待的线程2正好轮到了,要执行代码朝你要数据。但是你发现你目前的数据不足以提供给他。于是你还得
将以上的套路重复一遍。 兄嘚,没数据呀,你先等会,好了知会你一声,把锁给我,下一位请进!
于是线程2也歇着了。线程3进来了,但是它要的数据,恰好是你仅仅能够提供得了的。于是你把仅存的一点数据给了它,没有让他等,让他正常的走完你的整个同步方法。

例子:

package Thread;

public class ThreadWaitDemo {
   
	public static void main(String[] args) {
   
		Object s = "";	//为了测试执行wait对象的时候,导致当前线程等待之外,,放弃的那把锁到底是谁的锁,
		MyThread thread = new MyThread(s);
		synchronized (thread) {
   		//锁住了thread对象的锁
			try {
   
				System.out.println("开始等待计算");
				thread.start();
//				s.wait();
				thread.wait();
				System.out.println("等待结束, total = " + thread.total);
			} catch (Exception e) {
   
			}
			
		}
		
	}

}

class MyThread extends Thread {
   
	Object string = null;
	MyThread(Object s){
   
		string = s;
	}
	public int total = 0;
	public  void run() {
   
		synchronized (this) {
   
			for (int i = 0; i < 101; i++) {
   
				total += i;
				System.out.println(i+"");
			}
			notify();
//			string.notify();
		}	
	}
}


在这里插入图片描述
在这里插入图片描述
哎,,,写代码的时候,,感觉到坑了!!果然实践很重要,会带出很多思维。什么坑呢??我写的时候,搞不清main 方法里的synchronized 括号里要的那把锁,,和 这一块的同步代码里 thread.wait(),,,为什么是thread调用wait??反正就是一个令当前线程放弃锁的操作,为什么偏偏调用thread的?和 synchronized括号里面的参数难道有什么规矩必须保持一致?还有好多其他的问题,主要集中于 notify 和 wait 之间调用,是不是有一个潜规则,不写就报错。。事实上我就这点试了一下,,的确报错了。 比如,我把main方法里面的thread.wait()方法注掉改为了 s.wait(), 同时把 MyThread 的run方法里面的notify改成了同一个对象的notify(),要凑凑一对,想着反正wait就是暂停当前线程并还线程所在锁的,,即使我用s调出wait(),那也得放弃锁。。运行了一下,可以确定 s.wait() 方法执行了之后,主线程的确放弃了synchronized所持有的那把 thread 的锁,并且执行了 MyThread的run方法,但是但是,,string.notify()执行之后,,就仿佛没了消息!!最后一句“等待结束,,”死活打印不出来。所以推断出 wait 和 notify 肯定有一套规则!但是我这里看不到源码我的天。。咋整。
在这里插入图片描述
好吧,native的。。。
使用wait方法和notify方法用于线程间通信的正确姿势 这篇文章,可以说是条条命中!

嗷嗷我明白了,经过查阅,,wait, notify 这类方法, 所在的同步代码块,锁了谁,就应该用谁调!!!当在对象上调用wait()方法时,执行该代码的线程立即放弃这个线程持有的锁,然而调用notify时,并不意味着这时线程会放弃其锁。如果线程仍然在完成同步代码,则线程在移除之前都不会放弃锁。因此,notify并不意味着这时的锁变得可用。
例子:

/**
 * 要求:用wait 和 notify 确保两个线程一定先递加加后递减! 拒绝使用jion解决
 * @author forev
 *
 */
public class ThreadWaitDemo {
   
	public static boolean isAddOver = false;	//用于标志递加线程是否执行完毕。
	
	public static void main(String[] args
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

娅娅梨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值