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