多线程并发ThreadLocal使用实例

前提须知:ThreadLocal并不是用来解决多线程共享安全问题的!
网上的例子真的不能全信!有的例子2个,3个线程跑没问题,但是一旦达到一定数量则会出现问题!
 
 本人通过2个例子:
  第一个例子用来告诉你:ThreadLocal并不能解决多线程共享安全问题
    设计思路:创建一个ChangeInfo对象并设置name=“kkkk”,
起5个线程跑每个线程都把ChangeInfo对象保存在ThreadLocal中,
然后在从ThreadLocal中读取当前线程ChangeInfo对象的name值为,
然后再次更改ChangeInfo对象的name值为“aaaaa”。 
【如果说ThreadLocal能够解决多线程问题,那么每个线程最终的输出都是先输出:kkkk,
然后在输出:aaaaa|||||||如果说ThreadLocal不能够解决多线程问题,
那么当上一个线程改变了ChangeInfo对象的name值后,后面的线程两次输出则都是aaaaa】

  第二个例子:对于问题1如果来解决方案
public class ChangeInfo {
	
	private String name;

	public ChangeInfo(String str)
	{
		this.name=str;
	}
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
}
public class Demo implements Runnable {
	
	private    ChangeInfo changeInfo;
	final ThreadLocal local=new ThreadLocal();
	//通过构造方法把对象传过来
	public Demo(ChangeInfo changeInfo){
		this.changeInfo=changeInfo;
	}
	@Override
	public void run() {
		//先把对象引用放到ThreadLocal中保存
		local.set(changeInfo);
		//输出本线程中对象name属性
		System.out.println(Thread.currentThread().getName()+"该线程设置值之前>>>"+local.get().getName()+"|||||||||"+changeInfo);
		//更改本线程对象的Name属性
		local.get().setName("aaaaaaaaaa");
		System.out.println(Thread.currentThread().getName()+"该线程设置值之后来+++>>>"+local.get().getName()+"|||||||||"+changeInfo);
	}
public class Test {

	public static void main(String[] args) throws InterruptedException {
		ChangeInfo ChangeInfo=new ChangeInfo("KKKKK");
		Demo d=new Demo(ChangeInfo);
		Thread t1=new Thread(d);
		Thread t2=new Thread(d);
	Thread t3=new Thread(d);
	Thread t4=new Thread(d);
	Thread t5=new Thread(d);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
	
	}

}
运行结果如下:可以看出threadLocal Copy的是每个对象的【引用地址】,你每次都是修改同1个
地址的对象,你说能实现隔离作用吗???

Thread-0该线程设置值之前>>>KKKKK|||||||||com.single.ChangeInfo@b9e45a
Thread-1该线程设置值之前>>>KKKKK|||||||||com.single.ChangeInfo@b9e45a
Thread-0该线程设置值之后来+++>>>aaaaaaaaaa|||||||||com.single.ChangeInfo@b9e45a
Thread-1该线程设置值之后来+++>>>aaaaaaaaaa|||||||||com.single.ChangeInfo@b9e45a
Thread-3该线程设置值之前>>>aaaaaaaaaa|||||||||com.single.ChangeInfo@b9e45a
Thread-2该线程设置值之前>>>aaaaaaaaaa|||||||||com.single.ChangeInfo@b9e45a
Thread-2该线程设置值之后来+++>>>aaaaaaaaaa|||||||||com.single.ChangeInfo@b9e45a
Thread-4该线程设置值之前>>>aaaaaaaaaa|||||||||com.single.ChangeInfo@b9e45a
Thread-4该线程设置值之后来+++>>>aaaaaaaaaa|||||||||com.single.ChangeInfo@b9e45a
Thread-3该线程设置值之后来+++>>>aaaaaaaaaa|||||||||com.single.ChangeInfo@b9e45a
那么如何解决上述问题?
下面对上述例子做修改,ChangeInfo这个类不用修改,主要修改其他2个类。
public class Demo implements Runnable {
/*	
	private    ChangeInfo changeInfo;
	final ThreadLocal local=new ThreadLocal();
	//通过构造方法把对象传过来
	public Demo(ChangeInfo changeInfo){
		this.changeInfo=changeInfo;
	}*/
	
	@Override
	public void run() {
		//先把对象引用放到ThreadLocal中保存
	//	local.set(changeInfo);
		//输出本线程中对象name属性
		System.out.println(Thread.currentThread().getName()+"该线程设置值之前>>>"+Test.localThread.get().getName());
		//更改本线程对象的Name属性
	//	local.get().setName("aaaaaaaaaa");
		Test.localThread.get().setName("aaaaaaaa");
		System.out.println(Thread.currentThread().getName()+"该线程设置值之后来+++>>>"+Test.localThread.get().getName());
	}
public class Test {

	static ThreadLocal localThread=new ThreadLocal(){
		@Override
		protected ChangeInfo initialValue() {
			return new ChangeInfo("KKKKK");
		}
	};
	public static void main(String[] args) throws InterruptedException {
		//ChangeInfo ChangeInfo=new ChangeInfo("KKKKK");
	//	Demo d=new Demo(ChangeInfo);
		Demo d=new Demo();
		Thread t1=new Thread(d);
		Thread t2=new Thread(d);
	Thread t3=new Thread(d);
	Thread t4=new Thread(d);
	Thread t5=new Thread(d);
		t1.start();
		t2.start();
		t3.start();
		t4.start();
		t5.start();
	}

}
运行结果如下,是不是实现了隔离的效果??建议大家自己看完之后一定要自己写一遍

Thread-0该线程设置值之前>>>KKKKK
Thread-0该线程设置值之后来+++>>>aaaaaaaa
Thread-1该线程设置值之前>>>KKKKK
Thread-1该线程设置值之后来+++>>>aaaaaaaa
Thread-3该线程设置值之前>>>KKKKK
Thread-3该线程设置值之后来+++>>>aaaaaaaa
Thread-2该线程设置值之前>>>KKKKK
Thread-2该线程设置值之后来+++>>>aaaaaaaa
Thread-4该线程设置值之前>>>KKKKK
Thread-4该线程设置值之后来+++>>>aaaaaaaa
1、ThreadLocal 并不解决多线程 共享 变量的问题。既然变量不共享,那就更谈不上同步的问题。
2、同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本实例
3、ThreadLocal 隔离的实现必要条件:set进入ThreadLocal 中应该是实例,而不应该是对象的引用!

 

你可能感兴趣的:(后台开发)