版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/baidu_37378518/article/details/85776540
等待/通知机制
public final native void wait(long timeout) throws InterruptedException;
/* @throws IllegalMonitorStateException if the current thread is not
* the owner of the object's monitor.
* @throws InterruptedException if any thread interrupted the
* current thread before or while the current thread
* was waiting for a notification. The <i>interrupted
* status</i> of the current thread is cleared when
* this exception is thrown.
*/
public final void wait() throws InterruptedException {
wait(0);
}
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
wait()使当前执行代码的线程进行等待,是Object类方法,且在wait()所在代码行处停止执行,直到接到通知或被中断。 只能在同步方法或同步块中调用。当前线程会释放锁
//随机唤醒一个呈现wait状态的线程
public final native void notify();
//唤醒所有,优先级最高的最先执行,但也可能是随机执行,取决于虚拟机的实现
public final native void notifyAll();
执行notify()后,要等到线程退出synchronized代码块后,才会释放锁,而呈现wait状态的线程才可以获取该对象。如果该对象没有发出notify或notifyAll,则阻塞在wait状态仍旧会继续阻塞。如果发出notify时没有处于阻塞的线程,则该命令会被忽略。
每个锁对象都有两个队列:
- 就绪队列,存储将要获得锁的线程,线程被唤醒后才会进入,等待CPU调度
- 阻塞队列,存储了被阻塞的线程,被wait后进入,等待下一次唤醒
方法join的使用
join()作用:让“主线程”等待“子线程”结束之后才能继续运行
/*@throws InterruptedException
如果当前线程被中断,则抛出该异常
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
public final synchronized void join(long millis, int nanos)
throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
millis++;
}
join(millis);
}
public final void join() throws InterruptedException {
join(0);
}
对join()源码的理解:
当在主线程mainThread中调用一个线程testThread的join()时,由于join()是同步的(synchronized修饰),那么mainThread就会持有锁。
阅读源码可知,join()是利用isAlive()和wait(0)方法来使线程等待。由于mainThread持有了锁,则就会占有CPU资源,然后wait(0)方法是使当前线程等待,那么就正好让mainThread开始等待。
对于isAlive()方法,判断的是调用该方法的线程,即testThread线程。
然后该源码就达到了目的效果。
join(long)与sleep(long):join(long)内部使用wait(long)实现,具有释放锁的特点
类ThreadLocal的使用
主要解决每个线程绑定自己的值,可以将其类比成全局存放数据的盒子,盒子中可以存储每个线程的私有数据
ThreadLocal {
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
//用于子类复写该方法,设定默认值
protected T initialValue() {
return null;
}
//...
}