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
ThreadLocal原理:
ThreadLocal内部有一个内部类ThreadLocalMap;ThreadLocalMap的内部有一个Entry内部类,ThreadLocalMap内部类维护了一个Entry数组,Entry(类似Map.Entry)key是ThreadLocal,value是Object;每一个线程都有一个ThreadLocalMap的实例,这个ThreadLocalMap内部又有一个Entry数组,将threadLocal作为key获取每个线程中独立的副本,因为threadLocal可以有多个,所以Entry以数组的形式存放;
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
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,多个线程同时被唤醒。