java之Thread(1): join,wait,notify,sleep
上面是在网上看到的,忘记是哪个博客了,借用一下。
下面详细结束一下几个函数:
等待阻塞里面的wait和notify
-
wait和notify字面意思就是等待和通知。首先要明确等待和通知相对的对象是什么?是对象锁。wait是Object的方法,也就是每个Object其实都可以做一个对象锁,对应一个监视器(monitor).wait的时候,就是等待对象锁,notify的时候,也是通知对象锁可以用了。那么,wait和notify调用的地方必须也有同一个对象锁才行。这就是wait,notify的一个法则,要写在synchronize里面。如果wait和notify没有在synchronize里面,那么,就会报错:IllegalMonitorStateException。有个疑问,就是,如果不是synchronize里面,而是lock里面,可以吗?不行。因为lock实现不是加锁,是AQS
-
java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。 java内置锁是一个互斥锁,这
-
A线程里面调用wait的话,那么线程A会立即释放锁,进入阻塞状态,wait后面的代码也不会继续执行;但是线程B调用notify,会通知相应线程醒来,进入就绪状态,但是,这个时候,notify下面的代码会继续执行,知道这个线程所有的代码执行完,才会释放资源,这个时候才会让处于就绪状态的线程重新竞争资源。如果想让notify的线程也停下来,那就在前面加个wait。这也是为啥经典的消费者和生产者的问题,消费者和生产者线程里面,wait和notify都有。
其他阻塞里面的sleep:
-
sleep是Thread的静态函数,sleep()方法是让线程睡眠,此时并没有释放对象锁,其他想要拿到睡眠线程的对象锁的线程也就拿不到相应的对象锁,从而不能抢在它前面执行;wait()方法是让线程释放对象锁,不会占用cpu资源,当notify唤醒的时候,不一定是这个线程获取资源,这个由jvm决定。由于wait方法是在Object上的,而sleep方法是在Thread上,当调用Thread.sleep时,并不能改变对象的状态,因此也不会释放锁。
-
调用方法Thread.sleep();
-
调用sleep也是进入阻塞状态。
让步:yield
-
yield是Thread的函数,调用方法也就是Thread.yield()。yield表示愿意把处理器资源让出去,自己进入可运行线程池。
-
yield调用后进入可运行状态。也就是此现场还是可运行状态,和其他可运行状态的线程随机被cpu挑选。
-
jdk 的api上面结束yield方法的时候,A hint to the scheduler that the current thread is willing to yield its current use of a processor. 这意味着,其实可能没有效果。也就是这是一个倾向,但是现在的线程也可以执行完自己的事再把资源让给另一个线程。自己测试的时候就是这样。本来打算再consumer-provider里面使用互相谦让这种,结果效果出不来。
-
yield源码是调用native方法。
-
jdk不推荐使用此方法。毕竟,掷色子不符合不是0就是1的计算机的世界观。
半路加入:join
-
Waits for this thread to die.,只有一句话,在jdk里面,对于join()
-
调用方法:threadName.join; 调用join方法后,本线程阻塞。和wait一样,因为join源码就是调用wait
join 是合并线程。(当线程中使用t.join的意思就是说,执行完当前的线程,才能执行其他线程。)
join方法的源码会引起疑惑,就是究竟哪个线程应该阻塞。
wait是把调用线程阻塞在锁那里,这里调用线程指的是调用wait方法的线程。a.wait(),调用线程不是a,而是a.wait所在的线程。要知道,a可以不是线程,只不过join这里恰巧a是一个线程,但是a扮演的角色依旧是对象锁。
假如在main方法中有个线程A,执行了A.join(),那么线程A继续执行,而main线程这阻塞在A.join()处,直到线程A执行完毕并正常退出,此时main方法中的A.join()才返回,然后继续执行A.join()后面的代码
练习代码:
https://github.com/kaikai7654321/JavaStudy,
ConcurrentProgram下面的com.kaikai.java.concurrent.thread里面。