1. 程式人生 > 其它 >ThreadLocal 和 Countdaowlatch

ThreadLocal 和 Countdaowlatch

簡單學習下countDownLatch 和 ThreadLocal

ThreadLocal 和 Countdaowlatch

ThreadLocal

ThreadLocal提供了執行緒記憶體儲變數的能力,這些變數不同之處在於每一個執行緒讀取的變數是對應的互相獨立的。通過get和set方法就可以得到當前執行緒對應的值。

    public void set(T var1) {
        Thread var2 = Thread.currentThread();
        ThreadLocal.ThreadLocalMap var3 = this.getMap(var2);
        if (var3 != null) {
            var3.set(this, var1);
        } else {
            this.createMap(var2, var1);
        }
    }

 public T get() {
        Thread var1 = Thread.currentThread();
        ThreadLocal.ThreadLocalMap var2 = this.getMap(var1);
        if (var2 != null) {
            ThreadLocal.ThreadLocalMap.Entry var3 = var2.getEntry(this);
            if (var3 != null) {
                Object var4 = var3.value;
                return var4;
            }
        }
        return this.setInitialValue();
    }
public void remove() {
        ThreadLocal.ThreadLocalMap var1 = this.getMap(Thread.currentThread());
        if (var1 != null) {
            var1.remove(this);
        }

    }

ThreadLocal往往用來實現變數線上程之間的隔離

建立一個ThreadLocal物件,指定儲存的資料為integer,初始值為100

package Thread;

public class ThreadLocalTest {

    static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
        @Override
        protected Integer initialValue() {
            return 100;
        }
    };

    static class ADDThread extends Thread{
        @Override
        public void run() {
            Integer integer = threadLocal.get();
            System.out.println(Thread.currentThread().getName()+"----初始值----"+integer);

            integer +=100;
            System.out.println(Thread.currentThread().getName()+"----執行緒 操作int+100 ----");

            threadLocal.set(integer);
            System.out.println(Thread.currentThread().getName()+"----呼叫set存放新的integer到threadlocal,儲存修改");

            System.out.println(Thread.currentThread().getName()+"----當前執行緒的副本值"+threadLocal.get());

        }
    }

    static class SubThread extends Thread{
        @Override
        public void run() {
            Integer integer = threadLocal.get();
            System.out.println(Thread.currentThread().getName()+"----初始值----"+integer);
        }
    }
    public static void main(String[] args) {
        new ADDThread().start();
        new SubThread().start();
    }
}
================================================================
Thread-0----初始值----100
Thread-0----執行緒 操作int+100 ----
Thread-0----呼叫set存放新的integer到threadlocal,儲存修改
Thread-0----當前執行緒的副本值200
Thread-1----初始值----100

Countdaowlatch

  • countDownLatch是在java1.5被引入,跟它一起被引入的工具類還有CyclicBarrier、Semaphore、concurrentHashMap和BlockingQueue。
  • 存在於java.util.cucurrent包下。

countDownLatch這個類使一個執行緒等待其他執行緒各自執行完畢後再執行。

是通過一個計數器來實現的,計數器的初始值是執行緒的數量。每當一個執行緒執行完畢後,計數器的值就-1,當計數器的值為0時,表示所有執行緒都執行完畢,然後在閉鎖上等待的執行緒就可以恢復工作了。

//呼叫await()方法的執行緒會被掛起,它會等待直到count值為0才繼續執行
public void await() throws InterruptedException { };   
//和await()類似,只不過等待一定的時間後count值還沒變為0的話就會繼續執行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
//將count值減1
public void countDown() { };  

例項:

package Thread;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchTest {
    public static void main(String[] args) {
        final CountDownLatch latch = new CountDownLatch(2);
        System.out.println("Main Thread start run....");
        // first thread run
        ExecutorService es1 = Executors.newSingleThreadExecutor();
        es1.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                    System.out.println("fist thread :" + Thread.currentThread().getName() + "run ..");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                latch.countDown();
            }
        });
        es1.shutdown();
        // second thread run
        ExecutorService es2 = Executors.newSingleThreadExecutor();
        es2.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("second Thread : " + Thread.currentThread().getName() + " run ");
                latch.countDown();
            }
        });
        es2.shutdown();
        System.out.println("wait two thread finished");
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main thread run !!");
    }
}
===============================================
Main Thread start run....
wait two thread finished
fist thread :pool-1-thread-1run ..
second Thread : pool-2-thread-1 run 
main thread run !!

CountDownLatch的用法
CountDownLatch典型用法1:某一執行緒在開始執行前等待n個執行緒執行完畢。將CountDownLatch的計數器初始化為n new CountDownLatch(n) ,每當一個任務執行緒執行完畢,就將計數器減1 countdownlatch.countDown(),當計數器的值變為0時,在CountDownLatch上 await() 的執行緒就會被喚醒。一個典型應用場景就是啟動一個服務時,主執行緒需要等待多個元件載入完畢,之後再繼續執行。

CountDownLatch典型用法2:實現多個執行緒開始執行任務的最大並行性。注意是並行性,不是併發,強調的是多個執行緒在某一時刻同時開始執行。類似於賽跑,將多個執行緒放到起點,等待發令槍響,然後同時開跑。做法是初始化一個共享的CountDownLatch(1),將其計數器初始化為1,多個執行緒在開始執行任務前首先 coundownlatch.await(),當主執行緒呼叫 countDown() 時,計數器變為0,多個執行緒同時被喚醒。