ThreadLocal的简单使用
public class Test {
static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<SimpleDateFormat>();
static class MyTask implements Runnable {
static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
int i = 0;
public MyTask(int i) {
this.i = i;
}
@Override
public void run() {
if (t1.get() == null) {
t1.set(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
try {
// synchronized (sdf) {
// 在未加锁的状况下,极可能会出现异常,sdf 并不是线程安全的,
// 在每一个线程中共享的sdf未必能加载完毕
// 原子性未能保证
Date t2 = sdf.parse("2018-01-29");
System.out.println(t2);
// }
Date t = t1.get().parse("2018-01-29 10:27:" + i % 60);
System.out.println(i + ":" + t);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
MyTask r1 = new MyTask(100);
ExecutorService exs = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
exs.execute(r1);
}
}
}
ThreadLocal的时间效率
public class Test {
public static final int gen_count = 4000000;
public static final int nthread = 10;
static ExecutorService exs = Executors.newFixedThreadPool(nthread);
//多线程共享一个random 对象
//Random 是线程安全的
public static Random rnd = new Random(123);
public static ThreadLocal<Random> tRnd = new ThreadLocal<Random>() {
@Override
protected Random initialValue() {
return new Random(123);
}
};
static class MyTask implements Callable<Long> {
private int mode = 0;
public MyTask(int mode) {
this.mode = mode;
}
public Random getRandom() {
if (mode == 0) {
return rnd;
} else if (mode == 1) {
return tRnd.get();
}
return null;
}
@Override
public Long call() throws Exception {
long b = System.currentTimeMillis();
for (long i = 0; i < gen_count; i++) {
getRandom().nextInt();
}
long e = System.currentTimeMillis();
//System.out.println(Thread.currentThread().getName() + "耗时: " + (e - b));
return e - b;
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
Future<Long>[] futs = new Future[nthread];
for (int i = 0; i < nthread; i++) {
futs[i] = exs.submit(new MyTask(0));
}
long totaltime = 0;
for (int i = 0; i < nthread; i++) {
totaltime += futs[i].get();
}
System.out.println("多线程访问同一个Random实例" + totaltime);
totaltime = 0;
for (int i = 0; i < nthread; i++) {
futs[i] = exs.submit(new MyTask(1));
}
for (int i = 0; i < nthread; i++) {
totaltime += futs[i].get();
}
System.out.println("使用ThreadLocal包装Random实例" + "耗时: " + totaltime);
exs.shutdown();
}
}
实验结果
多线程访问同一个Random实例耗时: 27669
使用ThreadLocal包装Random实例耗时: 1285
Thread:ocal实现原理浅析
set 方法
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
get方法
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
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();
}