`
gengu
  • 浏览: 84813 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

ThreadLocal类的理解与使用

阅读更多

在java线程中有一个很有作用的类ThreadLocal

 

在网上关于ThreadLocal的理解也相当的多,文章也很多,但是很多看了都让人一头雾水,有的就讲原理,有的就说概念,而且大量的转载,却很少有实例这块的。

 

JDK1.5之后,java引入了泛型的概念,也为ThreadLocal引入了泛型,通过泛型可以简化多线程编程时的并发访问,使用这个工具类可以很简洁的编写出有没的多线程程序。

 

ThreadLocal 是Thread Local Variable(线程局部变量)的意思,线程局部变量的功能非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,使每一个想成都可以独立的改变自己的副本,而不会和其他线程的副本冲突,从线程的角度看,就好像每一个线程都完全拥有该变量

ThreadLocal 类的用法很简单,它只提供了三个方法。

T get();返回此线程局部变量中当前线程副本中的值。

void remove();删除此线程局部变量中当前线程副本中的值。

void set(T value);设置此线程局部变量中当前线程副本中的值。

 

下面将通过两个程序的对比来说明ThreadLocal类的作用。

下面提供两个账户类

package test7;

public class Account {
	/**
	 * 定义一个ThreadLocal类变量
	 * 该变量将是一个线程局部变量,每个线程都会保留该变量的一个副本
	 */
	private ThreadLocal<String> name = new ThreadLocal<String>();
	public String getName() {
		return this.name.get();
	}
	public void setName(String name) {
		this.name.set(name);
	}
}

package test7;

public class Account1 {
	/**
	 * 定义一个ThreadLocal类变量
	 * 该变量将是一个线程局部变量,每个线程都会保留该变量的一个副本
	 */
	private String name ;
	public String getName() {
		return this.name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

 

以上的账户类中只有name这一个属性,不同的是前者使用了ThreadLocal来存贮,后者就是一个String

 

下面是线程类

package test7;

public class Thread2 extends Thread{
	private Account1 account;
	public Thread2(Account1 account,String name){
		super(name);
		this.account = account;
	}
	@Override
	public void run(){
		for (int i = 0; i < 10; i++) {
			//当i为6的时候将当前账户名换成当前线程名
			if(i == 6){
				this.account.setName(getName());
			}
			System.out.println(account.getName()+"账户的i的值为"+i);
		}
	}
}

 这个类,是对每个账户进行操作,当运行到6的时候就将账户名改为当前线程的名字(getName()是Thread类中定义的方法)。

场景类是这样的

package test7;

public class Test7 {

	public static void main(String[] args) {
		Account1 account = new Account1();
		Thread thread1 = new Thread2(account,"xby");
		Thread thread2 = new Thread2(account,"gengu");
		thread1.start();
		thread2.start();
	}
}

 

如果使用Account1的话会出现什么结果?

null账户的i的值为0
null账户的i的值为1
null账户的i的值为2
null账户的i的值为3
null账户的i的值为4
null账户的i的值为5
xby账户的i的值为6
xby账户的i的值为7
xby账户的i的值为8
xby账户的i的值为9
xby账户的i的值为0
xby账户的i的值为1
xby账户的i的值为2
xby账户的i的值为3
xby账户的i的值为4
xby账户的i的值为5
gengu账户的i的值为6
gengu账户的i的值为7
gengu账户的i的值为8
gengu账户的i的值为9

 如果使用Account类那么会出现什么结果?

null账户的i的值为0
null账户的i的值为1
null账户的i的值为2
null账户的i的值为3
null账户的i的值为4
null账户的i的值为5
xby账户的i的值为6
xby账户的i的值为7
xby账户的i的值为8
xby账户的i的值为9
null账户的i的值为0
null账户的i的值为1
null账户的i的值为2
null账户的i的值为3
null账户的i的值为4
null账户的i的值为5
gengu账户的i的值为6
gengu账户的i的值为7
gengu账户的i的值为8
gengu账户的i的值为9

 不知道你们看出差别没有,就是后者相对非常独立,第一次accout变量的name属性改变之后没有使第二个线程中的account name变量改变。还是null,这回应该有点了解了吧。第一次运行的时候,线程1改变了线程2中account变量的name属性。

 

这样就好像,两个线程各拥有一个account实例一样。

 

但是ThreadLocal不能替代同步机制,因为他不能解决同步问题,只能解决共享安全问题,从根本上避免了多个线程之间的资源共享,所以也就不需要同步了。

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics