当前位置:首页 > 开发 > 编程语言 > 多线程 > 正文

线程范围内的共享数据 ThreadLocal 分析与详解

发表于: 2014-08-30   作者:annan211   来源:转载   浏览次数:
摘要: Java 线程范围内的数据共享机制,需要解决的问题是  : 多个业务模块针对同一个static变量的操作 要保证在不同线程中 各模块操作的是自身对应的变量对象 实例  A  B 两个类 需要操作同一个static变量 data 初步代码 可能如下: package threadLocal; import java.util.
Java 线程范围内的数据共享机制,需要解决的问题是  : 多个业务模块针对同一个static变量的操作 要保证在不同线程中 各模块操作的是自身对应的变量对象


实例  A  B 两个类 需要操作同一个static变量 data


初步代码 可能如下:

  package threadLocal;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * 线程范围内的共享数据
 * @author jingfn
 *
 */
public class ThreadScopeShareDate {
	private static int data ;
	public static void main(String[] args) {
		for(int i=0;i<2;i++)
		new Thread(new Runnable(){
			public  void run(){
					data = new Random().nextInt();
					System.out.println(Thread.currentThread().getName()+"--put data "+data);
					new A().get();
					new B().get();
				}
		}).start();
	}

	static class A{
		private void get(){
			System.out.println("A--get data from "+Thread.currentThread().getName()+" of "+data);
		}
	}
	static class B{
		private void get(){
			System.out.println("B--get data from "+Thread.currentThread().getName()+" of "+data);
		}
	}
}



执行结果:
  Thread-0--put data 350455289
Thread-1--put data -1313940209
A--get data from Thread-0 of -1313940209
A--get data from Thread-1 of -1313940209
B--get data from Thread-1 of -1313940209
B--get data from Thread-0 of -1313940209


分析结果可以看出 线程0 赋值数据  350455289,线程1 赋值数据  -1313940209,模块AB 拿到的data  却只是线程1 赋值的结果,这就说明在线程 0 赋值之后,AB操作之前,线程1 就已经将data的值修改为  -1313940209 了。


简单一点的修改 可以如下:

  package threadLocal;

import java.util.Random;

/**
 * 线程范围内的共享数据
 * @author jingfn
 *
 */
public class ThreadScopeShareDate {
	private static int data ;
	public static void main(String[] args) {
		for(int i=0;i<2;i++)
		new Thread(new Runnable(){
			public  void run(){
				synchronized(ThreadScopeShareDate.class){
					data = new Random().nextInt();
					System.out.println(Thread.currentThread().getName()+"--put data "+data);
					new A().get();
					new B().get();
				}
			}
		}).start();
	}

	static class A{
		private void get(){
			System.out.println("A--get data from "+Thread.currentThread().getName()+" of "+data);
		}
	}
	static class B{
		private void get(){
			System.out.println("B--get data from "+Thread.currentThread().getName()+" of "+data);
		}
	}
}



结果如下 
Thread-0--put data -30716152
A--get data from Thread-0 of -30716152
B--get data from Thread-0 of -30716152
Thread-1--put data 913737008
A--get data from Thread-1 of 913737008
B--get data from Thread-1 of 913737008


将数据与当前线程相挂钩的话 那么显然是可以利用ThreadLocal这个类
ThreadLocal 就相当于一个 Map,key就是当前线程,value为当前线程对应的值, 那么改造上面的代码得到下面的代码:
 package threadLocal;

import java.util.Random;

/**
 * 线程范围内的共享数据
 * @author jingfn
 *
 */
public class ThreadScopeShareDate {
	private static int data ;
	private static ThreadLocal<Integer> localdata = new ThreadLocal<Integer>();
	public static void main(String[] args) {
		for(int i=0;i<2;i++)
		new Thread(new Runnable(){
			public  void run(){
				synchronized(ThreadScopeShareDate.class){
					data = new Random().nextInt();
					localdata.set(data);
					System.out.println(Thread.currentThread().getName()+"--put data "+data);
					new A().get();
					new B().get();
				}
			}
		}).start();
	}

	static class A{
		private void get(){
			System.out.println("A--get data from "+Thread.currentThread().getName()+" of "+localdata.get());
		}
	}
	static class B{
		private void get(){
			System.out.println("B--get data from "+Thread.currentThread().getName()+" of "+localdata.get());
		}
	}
}






代码执行完以后会得到同样的效果。

        接下来还有一个问题  上面一直讨论的是线程间共享一个变量 那么如果是多个变量呢?

        要直接ThreadLocal每次只能是一个变量和当前线程挂钩 如果有多个变量要和当前线程挂钩的话 就得生命多个ThreadLocal对象 这样子做很显然是不合理的。那如何处理呢?

        由于ThreadLocal可以并且只能和一个变量挂钩,那么我们可以将这个变量设置为一个变量的容器,容器中可以存在多个变量,这也就是将需要和当前线程绑定的变量封装到一个实体类中



package threadLocal;

import java.util.Random;

/**
 * 线程范围内的共享数据
 * @author jingfn
 *
 */
public class ThreadScopeShareDateContainer {
	private static int data ;
	public static void main(String[] args) {
		for(int i=0;i<2;i++)
		new Thread(new Runnable(){
			public  void run(){
				synchronized(ThreadScopeShareDateContainer.class){
					data = new Random().nextInt();
					Container.getInstance().setData1(data);
					Container.getInstance().setData2(data);
					System.out.println(Thread.currentThread().getName()+"--put data "+data);
					new A().get();
					new B().get();
				}
			}
		}).start();
	}

	static class A{
		private void get(){
			System.out.println("A--get data from "+Thread.currentThread().getName()+" of "+Container.getInstance().getData1()+"--"+Container.getInstance().getData2());
		}
	}
	static class B{
		private void get(){
			System.out.println("B--get data from "+Thread.currentThread().getName()+" of "+Container.getInstance().getData1()+"--"+Container.getInstance().getData2());
		}
	}
}

 class Container{
	 private int data1,data2;
	 private static ThreadLocal<Container> local = new ThreadLocal<Container>();
	 public static Container getInstance(){
		 Container container = local.get();;
		 if(container == null){
			 container = new Container();
			 local.set(container);
		 }
		 return container;
	 }
	public int getData1() {
		return data1;
	}
	public void setData1(int data1) {
		this.data1 = data1;
	}
	public int getData2() {
		return data2;
	}
	public void setData2(int data2) {
		this.data2 = data2;
	}


 }





  ThreadLocal 是并发程序的一种解决方案,他利用空间换时间,也就是为每个线程分配空间来实现多线程,ThreadLocal 完全不使用锁,因此他不是一种数据共享的锁。
从性能上来说,ThreadLocal 并不具备绝对的优势,但是作为一种完全不使用锁的多线程解决方案,在高并发的情况下,在一定程度上可以减少锁的竞争。

线程范围内的共享数据 ThreadLocal 分析与详解

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
线程的同步通信与线程范围内的数据共享问题 一、线程的同步通信 什么是线程的同步通信?他有什么作
一.概述 ThreadLocal是JDK的一个线程本地存储的类,我们可以把一些线程私有的数据写在ThreadLocal中
优缺点和使用注意事项: /* * ThreadLocal 用于每一个线程都有一个次线程对应的副本。“以空间换时
package com.itm.thread; import java.util.Random; public class ThreadScopeShareData { private s
package com.itm.thread; import java.util.Random; public class ThreadScopeShareData { private s
ThreadLocal的目的:为当前线程绑定一个值,解决线程安全问题。 ThreadLocal的实现方式(线程与值的
线程安全一直是程序猿们关注的焦点,多线程也一直是比较让人头疼的话题,想必大家曾经也遇到过各种
线程间共享数据无需竞争 原文 地址 作者 Trisha 译者:李同杰 LMAX Disruptor 是一个开源的并发框架
什么是ThreadLocal? 首先,ThreadLocal 不是用来解决共享对象的多线程访问问题的,一般情况下,通
原文地址:http://www.iteye.com/topic/777716 ThreadLocal<T>类在Spring,Hibernate等框架中
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号