除了控制资源的访问外, 还可以通过增加资源来保证线程安全,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();
}
}