聊聊Thread的状态与ThreadLocal

  • 时间:
  • 浏览:2
  • 来源:uu直播快3平台

public final native void notifyAll();

以下示例代码中,thread1先获得obj的锁,执行另一方的逻辑,thread2因此 获取必须锁一直阻塞;当thread1因此 wait()而停留时,释放了obj的所资源,此时thread2将之前 刚开始了了执行,thread2执行之前 通过notifyAll()唤醒在obj上停留的任务管理器池,此后thread1将继续执行。

 - 好多好多 任务管理器池interrupt任务管理器池T。

     synchronized (obj) {

11:05:26:875 Thread1 finished...



以下是set法律土办法的源码,代码逻辑比较简单,其逻辑是:因此 thread中threadLocals(ThreadLocal.ThreadLocalMap类型)属性为空,这么 创建另另一个 ThreadLocalMap对象,赋给thread.threadLocals;因此 直接使用此value值替换thread.threadLocals中的值。

public final void wait(long timeout, int nanos) throws InterruptedException { … }

    // Find either the key or trailing null slot of run, whichever

private void remove(ThreadLocal<?> key) {

    Entry[] tab = table;

    int len = tab.length;

    int i = key.threadLocalHashCode & (len-1);

    for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {

        if (e.get() == key) {

            e.clear();

            expungeStaleEntry(i);

            return;

        }

    }

}

 - 因此 是Class类型的对象,这么 执行此class的static法律土办法。

11:05:26:874 Thread2 executing...



           replaceStaleEntry(key, value, i);

            return;

        }

    }

    tab[i] = new Entry(key, value);

 -  到了指定时间。因此 参数timeout=0,这么 时间参数因此 被忽略,即此时必须通之前 面 这一 法律土办法唤醒。

void createMap(Thread t, T firstValue) {

    t.threadLocals = new ThreadLocalMap(this, firstValue);

}

亲戚当当当我们 歌词 假设而是这一 情况:假设ThreadLocal对象不再被引用了,这么 JVM如可回收ThreadLocalMap中存储的数据呢?

private void set(ThreadLocal<?> key, Object value) {

    Entry[] tab = table;

    int len = tab.length;

    int i = key.threadLocalHashCode & (len-1);

    for (Entry e = tab[i];

         e != null;

         e = tab[i = nextIndex(i, len)]) {

        ThreadLocal<?> k = e.get();

        if (k == key) {

            e.value = value;

            return;

        }

        if (k == null) {

       //清理掉陈旧Entry,并设置为当前的新值,这一 Entry是因此 ThreadLocal变量对象被回收后k==null造成的

ThreadLocalMap#set法律土办法

ThreadLocalMap#getEntryAfterMiss法律土办法

ThreadLocal#remove

    if (millis == 0) {

/**

 * Waits at most {@code millis} milliseconds for this thread to die. A timeout of {@code 0} means to wait forever.

 */

public final synchronized void join(long millis)

throws InterruptedException {

    long base = System.currentTimeMillis();

    long now = 0;

    if (millis < 0) {

            tab[i] = tab[staleSlot];

在之前 讨论任务管理器池-基础知识的之前 ,完整讲述过java的任务管理器池模型、任务管理器池情况流转、任务管理器池安全再次出先的原因分析以及防止法律土办法,好多好多 有这里太大过的讨论这一 块。此小节的重点从源码的深度上看看哪几种地方会引起任务管理器池情况变化。

               System.out.println(DateUtil.getCurrentTime() + " Thread1 finished...");

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

    });

    thread1.start();

    Thread thread2 = new Thread(() -> {

        synchronized (obj) {

            System.out.println(DateUtil.getCurrentTime() + " Thread2 executing...");

            obj.notifyAll();

        }

    });

    thread2.start();

}

        // If we didn't find stale entry on backward scan, the

11:05:26:874 Thread1 begin wait...

ThreadLocalMap#remove

 - 好多好多 任务管理器池调用notifyAll()法律土办法。

和wait一样,notify、notifyAll也需要装到 sycronized实物,因此 会报“java.lang.IllegalMonitorStateException”异常。示例代码如下:

     synchronized (obj) {

Object中的wait、notify也会影响任务管理器池情况,好多好多 有这里也就一起去介绍了。值得一提的是JDK还提供了LockSupport类,此类中的park和unpark法律土办法都都上能实现和wait、notify类式的功能。具体请参考:LockSupport

ThreadLocal#set法律土办法

注意:wait()一定要装到 sycronized实物,因此 会报“java.lang.IllegalMonitorStateException”异常。这是因此 wait法律土办法会释放对象锁,好多好多 有因此 这么 使用sycronized同步时,因此 这么 锁就会报异常。示例代码如下:

public void set(T value) {

    Thread t = Thread.currentThread();

    ThreadLocalMap map = getMap(t);

    if (map != null)

        map.set(this, value);

    else

        createMap(t, value);

}

让当前任务管理器池(假设是T)停留直到好多好多 任务管理器池调用notify()、notifyAll()因此 停留超过指定的时间。

 - 当任务管理器池位于Waiting情况时,任务管理器池太大获取CPU资源。

    public static native void yield();

图中Waiting、Blocking的区别是:

 - 通过执行object的synchronized代码块。

ThreadLocal#get法律土办法

public static void main(String[] args) {

    System.out.println("Main Thread start....");

    Thread thread = new Thread(() -> {

        System.out.println("Child Thread start...");

        try {

            Thread.sleep(30000);

        } catch (Exception e) {

            e.printStackTrace();

        }

        System.out.println("Child Thread finished...");

    });

执行结果如下:

        // If we find key, then we need to swap it

当调用object.notify()法律土办法时:因此 多个任务管理器池完整回会停留object对象的锁,这么 唤醒其中的另另一个 (一般而言是随机的唤醒,具体需要看底层的实现)。此法律土办法仅都都都上能被拥有此object对象锁的任务管理器池调用,必须以下这一 情况,任务管理器池都都上能拥有对象的锁:

 - 通过执行另另一个 object对象synchronized的实例法律土办法。

 - Thread实物的Map是由ThreadLocal维护的,由ThreadLocal负责向map获取和设置任务管理器池的变量值。

从图中能必须看后ThreadLocal通过Thread.currentThread()获取当前任务管理器池,并操作任务管理器池持有的ThreadLocalMap对象。总结一下:

注意ThreadLocalMap中的getEntry、getEntryAfterMiss法律土办法,为哪几种亲戚当当当我们 歌词 set进去的value,之前 取的之回会再次出先key为空的情况?这是因此 ThreadLocalMap#Entry对象的key是WeakReference<ThreadLocal<?>>类型的,此种类型的引用,因此 这么 好多好多 引用了,这么 在GC的之回会被回收掉(当然因此 此对象「key」还有好多好多 有效引用,对象将太大被回收);因此 value是普通类型的引用,当GC时因此 key被回收了,这么 因此 清理掉此Entry的值。

ThreadLocal一直用来存储任务管理器池私有变量。

public final native void wait(long timeout) throws InterruptedException;

ThreadLocalMap#getEntry法律土办法

            obj.wait(timeout);

private void replaceStaleEntry(ThreadLocal<?> key, Object value,

                               int staleSlot) {

    Entry[] tab = table;

    int len = tab.length;

    Entry e;

    // Back up to check for prior stale entry in current run.

public final void wait() throws InterruptedException{…}

Entry的部分代码如下所示

public void remove() {

    ThreadLocalMap m = getMap(Thread.currentThread());

    if (m != null)

        m.remove(this);

}

11:05:25:836 Thread1 start...

 任务管理器池情况

让任务管理器池休眠指定时间,休眠时不放弃任务管理器池持有的资源。

    // If key not found, put new entry in stale slot

         ... // Perform action appropriate to condition

private Entry getEntry(ThreadLocal<?> key) {

    int i = key.threadLocalHashCode & (table.length - 1);

    Entry e = table[i];

    if (e != null && e.get() == key)

        return e;

    else

        return getEntryAfterMiss(key, i, e);

}

让当前任务管理器池停留,直到调用join法律土办法的任务管理器池执行完毕后再执行,类式:在threadA中调用threadB.join()法律土办法,就表示让threadA停留threadB执行完成,因此 threadB再继续执行。从下面的代码中亲戚当当当我们 歌词 能必须看后,join嘴笨 调用的时wait法律土办法,代码如下:

         ... // do the work

任务管理器池的threadLocals属性因此 非空,这么 从threadLocals中删除之前 存放的值。

            // Start expunge at preceding stale entry if it exists

public static void sleep(long millis, int nanos)  throws InterruptedException{…}

最好的防止法律土办法是,因此 某个value需要了,手动调用ThreadLocal#remove法律土办法删除,以免因此 这么 触发replaceStaleEntry()法律土办法,而必须回收value。

 - Map后面 存储任务管理器池本地对象(key)和任务管理器池的变量副本(value)

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;

}

static class Entry extends WeakReference<ThreadLocal<?>> {

    Object value;

    Entry(ThreadLocal<?> k, Object v) {

        super(k);

        value = v;

    }

}

public final native void notify();

ThreadLocalMap#replaceStaleEntry法律土办法是用来复用ThreadLocalMap中的数据,当某另另一个 ThreadLocal因此 被清理了,这么 就能必须用这一 空间来存储新的数据了。

private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {

    Entry[] tab = table;

    int len = tab.length;

    while (e != null) {

         while (<condition does not hold>)

出让cpu的执行时间,出让后和好多好多 任务管理器池一起去争抢CPU调度。

 - 当任务管理器池位于Blocking情况时,代表着任务管理器池能必须尝试获取CPU资源。

    // If there are any other stale entries in run, expunge them

任务管理器池T接着会从wait set中移除,接着将和好多好多 任务管理器池一样争取object的锁,一旦任务管理器池T获得了object的锁,因此 获得同步声明因此 立即从之前 的停留情况返回,继续执行亲戚当当当我们 歌词 的代码。

ThreadLocal一直用来存储任务管理器池私有变量,在另另一个 任务管理器池内能必须多次创建ThreadLocal对象,因此 哪几种ThreadLocal对象共用同另另一个 ThreadLocalMap的实例。以下是Thread、ThreadLocal、ThreadLocalMap之间的关系。

public static native void sleep(long millis) throws InterruptedException;

ThreadLocal#setInitialValue法律土办法

参考Interrupt

 - 好多好多 任务管理器池调用notify()法律土办法,因此 任务管理器池T正好的被唤醒。

notifyAll和notify类式,主要的区别是notifyAll会唤醒停留此对象锁的所有任务管理器池,因此 亲戚当当当我们 歌词 一起去争抢cpu资源。

     }

需要注意的是:ThreadLocalMap是任务管理器池私有的,见ThreadLocal#createMap()法律土办法。

当ThreadLocal这么被需要时,其在任务管理器池中存储的数据应该被GC回收掉,即任务管理器池中ThreadLocalMap里的key-value对应该失效。ThreadLocalMap#Entry中key是WeakReference<ThreadLocal<?>>类型,嘴笨 而是为了实现这一 诉求的。因此 key是WeakReference类型的应用,好多好多 有在GC的时,ThreadLocalMap中key会被回收,即被设置为null(注意此时因此 ThreadLocalMap引用value的关系,好多好多 有value太大被回收)。在后面 set、get等法律土办法中,亲戚当当当我们 歌词 看后的expungeStaleEntry、replaceStaleEntry、cleanSomeSlots法律土办法嘴笨 而是在挂接、回收ThreadLocalMap中因此 失效的key-value。因此 触发了expungeStaleEntry法律土办法,ThreadLocalMap中的数据就会被回收干净。

     }

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();

}

以下代码中,主任务管理器池将停留thread执行之前 刚开始了了,因此 再输出最后的之前 刚开始了了信息。

如下代码,从任务管理器池的threadLocals属性中查找是与否位于需要的值,因此 位于,这么 返回,因此 不位于初始化任务管理器池的threadLocals。

public static void main(String[] args) {

    Object obj = new Object();

    Thread thread1 = new Thread(() -> {

        synchronized (obj) {

           System.out.println(DateUtil.getCurrentTime() + " Thread1 start...");

            try {

                Thread.sleep(30000);

               System.out.println(DateUtil.getCurrentTime() + " Thread1 begin wait...");

                obj.wait();

 - 每个Thread任务管理器池实物完整回会另另一个 Map。

             obj.notify(timeout);

当执行object.wait()法律土办法时,将当前任务管理器池T装到 此object对象的wait set中,因此 放弃持有的资源,这一 任务管理器池T将不再被cup调度,直到以下任意另另一个 事情位于:

ThreadLocal#createMap法律土办法