方法wait()的做用是使当前线程进行等待,wait()方法是Object类的方法,该方法用来将当前线程放到“预执行队列”,并在wait()所在的代码处中止执行,直到接到通知或中断为止。只能在同步方法或同步快中使用wait()方法,执行wait()后,当前线程释放锁。java
方法notify()也要在同步方法或同步快中调用,在调用前也必须得到该对象的的对象级别锁。该方法用来通知那些可能等待该对象的对象锁的其余线程,若是有多个线程等待,则由线程规划器随机选出一个wait状态的线程,对其发出notify通知,使他等待获取对象锁。git
在执行notify()后当前线程不会立刻释放锁,会在线程退出synchronized代码块才会释放锁,呈wait状态的线程才能够获取锁。当第一个获取对象锁的wait线程运行结束释放锁后,若是该对象没有再次notify,其余wait状态的线程依然会阻塞wait状态,直到这个对象发出notify或notifyAll。github
public class MyWait {
private final Object lock;
MyWait(Object lock){
this.lock=lock;
}
public void waitTest(){
try {
synchronized (lock){
System.out.println("开始 wait time = " + System.currentTimeMillis());
lock.wait();
System.out.println("结束 wait time = " + System.currentTimeMillis());
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
复制代码
public class MyNotify {
private final Object lock;
MyNotify(Object lock){
this.lock=lock;
}
public void notifyTest(){
synchronized (lock){
System.out.println("开始 notify time = " + System.currentTimeMillis());
lock.notify();
System.out.println("结束 notify time = " + System.currentTimeMillis());
}
}
}
复制代码
public class Main {
public static void main(String[] args){
try {
Object lock = new Object();
MyWait myWait = new MyWait(lock);
new Thread(() -> myWait.waitTest()).start();
Thread.sleep(3000);
MyNotify myNotify = new MyNotify(lock);
new Thread(() -> myNotify.notifyTest()).start();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
复制代码
开始 wait time = 1552812964325
开始 notify time = 1552812967328
结束 notify time = 1552812967328
结束 wait time = 1552812967328
复制代码
从输出内容能够看出3秒后执行notify方法,并在notify方法执行结束后才执行wait后的方法。bash
新建(new):新建立了一个线程对象。微信
可运行(runnable):线程对象建立后,其余线程(好比main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获 取cpu的使用权。ide
运行(running):可运行状态(runnable)的线程得到了cpu时间片(timeslice),执行程序代码。ui
阻塞(block):阻塞状态是指线程由于某种缘由放弃了cpu使用权,也即让出了cpu timeslice,暂时中止运行。直到线程进入可运行(runnable)状态,才有 机会再次得到cpu timeslice转到运行(running)状态。阻塞的状况分三种:this
(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放 入等待队列(waitting queue)中。spa
(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁 被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。.net
(三). **其余阻塞**: 运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时join()等待线程终止或者超时、或者I/O处理完毕时,线程从新转入可运行(runnable)状态。
复制代码
本节代码GitHub
在不少状况,主线程建立并启动子线程,若是子线程中进行大量的耗时运算,主线程每每将遭遇子线程结束以前结束。若是主线程要等待子线程执行完成以后在结束,就要使用join()方法,join()做用是等待线程对象销毁。
Thread类除了提供join()方法以外,还提供了join(long millis)、join(long millis, int nanos)两个具备超时特性的方法。这两个超时方法表示,若是线程thread在指定的超时时间没有终止,那么将会从该超时方法中返回。
public class Main {
public static void main(String[] args) throws InterruptedException{
Thread thread = new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName()+"正在执行");
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
}, "线程1");
thread.start();
thread.join();
System.out.println("等待"+thread.getName()+"执行完");
}
}
// 输出
线程1正在执行
等待线程1执行完
复制代码
方法join(long)的功能是在内部使用wait(long)方法来实现的,因此join(long)方法具备释放锁的特色。二sleep(long)不会释放锁。
变量值共享可使用public static变量的形式,全部线程都使用同一个public static变量,若是想实现每一个线程都有本身的共享变量可使用ThreadLocal来解决。
ThreadLocal的相关方法:
public class ThreadLocalTeat {
public static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException{
int count = 30;
String name = "Thread-";
for (int i=0; i<count; i++){
Thread thread = new Thread(() -> {
threadLocal.set(Thread.currentThread().getName());
System.out.println(threadLocal.get());
}, name+i);
thread.start();
}
Thread.sleep(20000);
}
}
// 输出
Thread-0
Thread-4
Thread-3
Thread-6
Thread-2
Thread-1
Thread-7
。。。
复制代码
使用类InheritableThreadLocal能够在子线程中获取父线程继承下来的值。
public class InheritableThreadLocalTest extends InheritableThreadLocal {
@Override
protected Object childValue(Object parentValue) {
return super.childValue(parentValue);
}
@Override
protected Object initialValue() {
return System.currentTimeMillis();
}
}
复制代码
* @date 2019/6/18 8:28
* @description
*/
public class InheritableTeat {
static public class Inner{
public static InheritableThreadLocalTest threadLocalTest = new InheritableThreadLocalTest();
}
public static void main(String[] args) throws InterruptedException{
for (int i = 0; i<3; i++){
System.out.println("在main线程中获取值:"+ Inner.threadLocalTest.get());
}
for (int i=0; i<3; i++){
new Thread(() -> {
System.out.println("在"+Thread.currentThread().getName()+"中获取值:"+ Inner.threadLocalTest.get());
}, "Thread-"+i).start();
}
Thread.sleep(1000);
}
}
// 输出
在main线程中获取值:1560818029616
在main线程中获取值:1560818029616
在main线程中获取值:1560818029616
在Thread-1中获取值:1560818029616
在Thread-2中获取值:1560818029616
在Thread-0中获取值:1560818029616
复制代码
在使用InheritableThreadLocal类须要注意的一点是:若是子线程在取得值的同时,主线程将InheritableThreadLocal中的值进行更改,那么子线程取到的仍是旧值。
欢迎关注公众号: