【Java多线程编程核心技术】第三章 线程间通信

版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
    }
    
    //...
}

猜你喜欢

转载自blog.csdn.net/baidu_37378518/article/details/85776540