除了控制資源的訪問外, 還可以通過增加資源來保證線程安全,ThreadLocal主要解決為每個線程綁定自己的值。
package com.wkcto.threadlocal;
/**
* ThreadLocal的基本使用
*/
public class Test01 {
//定義ThreadLocal對象
static ThreadLocal threadLocal = new ThreadLocal();
//定義線程類
static class Subthread extends Thread{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
//設置線程關聯的的值
threadLocal.set( Thread.currentThread().getName() + " - " + i);
//調用get()方法讀取關聯的值
System.out.println(Thread.currentThread().getName() + " value = " + threadLocal.get());
}
}
}
public static void main(String[] args) {
Subthread t1 = new Subthread();
Subthread t2 = new Subthread();
t1.start();
t2.start();
}
}
package com.wkcto.threadlocal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 在多線程環境中,把字符串轉換為日期對象,多個線程使用同一個SimpleDateFormat對象可能會產生線程安全問題,有異常
* 為每個線程指定自己的SimpleDateFormat對象, 使用ThreadLocal
*/
public class Test02 {
//定義SimpleDateFormat對象,該對象可以把字符串轉換為日期
// private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
static ThreadLocal threadLocal = new ThreadLocal<>();
//定義Runnable接口的實現類
static class ParseDate implements Runnable{
private int i = 0 ;
public ParseDate(int i) {
this.i = i;
}
@Override
public void run() {
try {
String text = "2068年11月22日 08:28:" + i%60; //構建日期字符串
// Date date = sdf.parse(text); //把字符串轉換為日期
//先判斷當前線程是否有SimpleDateFormat對象,如果當前線程沒有SimpleDateFormat對象就創建一個,如果有就直接使用
if (threadLocal.get() == null){
threadLocal.set(new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"));
}
Date date = threadLocal.get().parse(text);
System.out.println(i + " -- " + date);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//創建100個線程
for (int i = 0; i < 100; i++) {
new Thread(new ParseDate(i)).start();
}
}
}
package com.wkcto.threadlocal;
import java.util.Date;
import java.util.Random;
/**
* ThreadLocal初始值, 定義ThreadLocal類的子類,在子類中重寫initialValue()方法指定初始值,再第一次調用get()方法不會返回null
*/
public class Test03 {
//1) 定義ThreadLocal的子類
static class SubThreadLocal extends ThreadLocal{
// 重寫initialValue方法,設置初始值
@Override
protected Date initialValue() {
// return new Date(); //把當前日期設置為初始化
return new Date(System.currentTimeMillis() - 1000*60*15);
}
}
//定義ThreadLocal對象
// static ThreadLocal threadLocal = new ThreadLocal();
//直接使用自定義的SubThreadLocal對象
static SubThreadLocal threadLocal = new SubThreadLocal();
//定義線程類
static class SubThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
//第一次調用threadLocal的get()方法會返回null
System.out.println("---------" + Thread.currentThread().getName() + " value=" + threadLocal
.get());
//如果沒有初始值就設置當前日期
if ( threadLocal.get() == null ){
System.out.println("*****************");
threadLocal.set(new Date());
}
try {
Thread.sleep(new Random().nextInt(500));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
SubThread t1 = new SubThread();
t1.start();
SubThread t2 = new SubThread();
t2.start();
}
}