标签:test 管理 -- style 结果 adl 线程 instance 类的设计
目标:如何保证各自线程上的数据是独立的,即A线程上数据只能被A线程操作
1:示例线程共享变量
我们先来看一个反例
package com.prepare.study;
import java.util.Random;
/**
* @author: yinlm
* @Date: Created in 2018/4/18
* @Description:多个线程数据混乱的示例
*/
public class ThreadTest2 {
// static 修饰 表示这是个全局变量
private static int data = 0;
public static void main(String[] args){
// 模拟有3个线程
for(int i=1;i<=3;i++){
new Thread(new Runnable() {
@Override
public void run() {
data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()+ " put data "+data);
// 同一个线程范围内去操作共享数据
new OtherA().getData();
new OtherB().getData();
}
}).start();
}
}
static class OtherA{
public void getData(){
System.out.println("A from "+ Thread.currentThread().getName()+" get " +data);
}
}
static class OtherB{
public void getData(){
System.out.println("B from "+ Thread.currentThread().getName()+" get " +data);
}
}
}
结果:数据乱了,Thread-0 put的数据,从线程0拿的数据是错误的
Thread-0 put data 830670045
Thread-1 put data -2139375952
Thread-2 put data -458533612
A from Thread-2 get -458533612
A from Thread-0 get -458533612
A from Thread-1 get -458533612
B from Thread-2 get -458533612
B from Thread-1 get -458533612
B from Thread-0 get -458533612
使用ThreadLocal类线程绑定来实现数据的线程独立。
package com.prepare.study;
import java.util.Random;
/**
* @author: yinlm
* @Date: Created in 2018/4/18
* @Description:
*/
public class ThreadTest2 {
// static 修饰 表示这是个全局变量
private static ThreadLocal<Integer> threadData = new ThreadLocal<>();
public static void main(String[] args){
// 模拟有3个线程
for(int i=1;i<=3;i++){
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()+ " put data "+data);
// 数据进行了线程绑定
threadData.set(data);
new OtherA().getData();
new OtherB().getData();
}
}).start();
}
}
static class OtherA{
public void getData(){
// 获取的是该线程绑定的数据
System.out.println("A from "+ Thread.currentThread().getName()+" get " +threadData.get());
}
}
static class OtherB{
public void getData(){
System.out.println("B from "+ Thread.currentThread().getName()+" get " +threadData.get());
}
}
}
2:ThreadLocal的使用
ThreadLocal用于实现线程内的数据共享,即对于相同的程序代码,对各模块在同一个线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据
(1) 每个线程调用全局ThreadLocal对象的set方法,就相当于往其内部的map中增加一条记录,key分别是各自的线程,value是各自的set方法传进去的值。在线程结束时候可以调用
ThreadLocal.clear()方法,这样会更快释放内存,不调用也可以,因为线程结束后也可以自动释放相关的ThreadLocal变量
总结:一个ThradLocal代表一个变量,故其中只能放一个数据,你有多个变量都要线程范围内共享则要定义多个ThreadLocal对象;或这把这多个变量封装成一个对象。
技巧一: 当然有一种更优雅的方法,把该对象的构造方法写成线程绑定的,(即让某个类针对不同线程创建一个独立的实例对象),如下代码。
实现对ThreadLocal变量的封装,让外界不要直接操作ThreadLocal 变量。
该类的设计模仿了单利模式的思想,单利是所有线程拿到的是同一个实例;而这个是每一个线程拿到的是各自独立的对象。
package com.prepare.study;
import java.util.Random;
/**
* @author: yinlm
* @Date: Created in 2018/4/18
* @Description:
*/
public class ThreadTest2 {
public static void main(String[] args){
// 模拟有3个线程
for(int i=1;i<=3;i++){
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName()+ " put data "+data);
// 该对象的实例本身就是线程绑定的
ThreadScopeUser.getThreadInstance().setName("name - "+data);
ThreadScopeUser.getThreadInstance().setAge(data);
// 模拟去操作数据
new OtherA().getData();
new OtherB().getData();
}
}).start();
}
}
static class OtherA{
public void getData(){
// 获取该线程绑定的实例
ThreadScopeUser scopeUser = ThreadScopeUser.getThreadInstance();
System.out.println("A from "+ Thread.currentThread().getName()+" get " + scopeUser.getName()+" "+scopeUser.getAge());
}
}
static class OtherB{
public void getData(){
ThreadScopeUser scopeUser = ThreadScopeUser.getThreadInstance();
System.out.println("A from "+ Thread.currentThread().getName()+" get " + scopeUser.getName()+" "+scopeUser.getAge());
}
}
}
// 该对象的创建就是为了线程独立的,那么线程独立就由此类来管理吧
class ThreadScopeUser{
private String name;
private Integer age;
// 构造方法私有,仿照单例写法
private ThreadScopeUser(){}
// 这样获取该实体的实例对象本身就是线程绑定的
public static ThreadScopeUser getThreadInstance(){
ThreadScopeUser userInstance = threadLocalUser.get();
if(userInstance == null){
userInstance = new ThreadScopeUser();
threadLocalUser.set(userInstance);
}
return userInstance;
}
private static ThreadLocal<ThreadScopeUser> threadLocalUser = new ThreadLocal<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
如何实现线程范围内共享数据 -- ThreadLocall类及其应用技巧
标签:test 管理 -- style 结果 adl 线程 instance 类的设计
原文地址:https://www.cnblogs.com/lemingyin/p/8877987.html