标签: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