线程内的数据共享与对象独立,举例:张三给李四转钱,开启A线程去执行转钱这个动作,刚好同时王五给赵六转钱,开启B线程去执行转钱,因为是调用的同样一个动作或者说对象,所以如果不能保证线程间的对象独立,那么很有可能发生,张三给李四转钱时把王五转给赵六的转钱一块提交了,而王五转钱整个动作还未完成,那么就造成了转钱错误,所以线程间一方面要保证数据的共享,另一方面要保证对象的对立.1.用Map封装对象以数据实现共享packagecom.amos.concurrent;importjava.util.HashMap;importjava.util.Map;importjava.util.Random;/***@ClassName:ThreadScopeShareData*@Description:下面的例子用的是Map对象将数据实现共享*@author:amosli*@email:hi_amos@outlook.com*@dateApr20,20146:19:02PM*/publicclassThreadScopeShareData{publicstaticMapObject,Integermap=newHashMapObject,Integer();publicstaticvoidmain(String[]args){for(inti=0;i3;i++){newThread(newRunnable(){publicvoidrun(){intdata=newRandom().nextInt();//给data设值,System.out.println(Thread.currentThread().getName()+setdata:+data);map.put(Thread.currentThread(),data);//将值按照Thread去设值,取的时候也按Thread去取,以保证数据的共享,但又保证了对象的独立.newA().get();newB().get();}}).start();}}staticclassA{//这里A和B的方法虽然是一样的,这里是想表示有可能调用不同的对象去执行数据操作publicintget(){data=map.get(Thread.currentThread());System.out.println(afromthread:+Thread.currentThread().getName()+is+data);returndata;}}{publicintget(){intdata=map.get(Thread.currentThread());System.out.println(bfromthread:+Thread.currentThread().getName()+is+data);returndata;}}}运行效果:2.使用ThreadLocal实现数据共享创建ThreadLocal,可以直接new出来,其设值支技泛型,newThreadLocalT,如下将上面代码改写:publicclassThreadLocalShareData{privatestaticThreadLocalIntegerthreadLocal=newThreadLocalInteger();publicstaticvoidmain(String[]args){for(inti=0;i3;i++){newThread(newRunnable(){publicvoidrun(){intdata=newRandom().nextInt();//给data设值,System.out.println(Thread.currentThread().getName()+setdata:+data);threadLocal.set(data);//使用ThreadLocal来设值newA().get();newB().get();}}).start();}}staticclassA{//这里A和B的方法虽然是一样的,这里是想表示有可能调用不同的对象去执行数据操作publicintget(){intdata=threadLocal.get();System.out.println(afromthread:+Thread.currentThread().getName()+is+data);returndata;}}classB.......}下面是ThreadLocalset(Tvalue)方法的源码:publicvoidset(Tvalue){Threadt=Thread.currentThread();ThreadLocalMapmap=getMap(t);if(map!=null)(this,value);elsecreateMap(t,value);}这里同样是用Map方式的设值,只不过又封装了一层ThreadLocalMap.查看其ThreadLocalget()方法的源码:publicTget(){Threadt=Thread.currentThread();ThreadLocalMapmap=getMap(t);if(map!=null){ThreadLocalMap.Entrye=map.getEntry(this);if(e!=null)return(T)e.value;}returnsetInitialValue();}同样是通过与线程绑定,取值的.3.实例测试packagecom.amos.concurrent;classAccount{/**定义一个ThreadLocal类型的变量,该变量是一个线程局部变量*/privateThreadLocalStringname=newThreadLocalString();//定义一个初始化name属性的构造器publicAccount(Stringstr){this.name.set(str);//下面的代码用于访问当前线程的name副本的值System.out.println(------+this.name.get());}//name的getter,setter方法publicStringgetName(){returnname.get();}publicvoidsetName(Stringstr){this.name.set(str);}}classMyTestextendsThread{//定义一个Account属性privateAccountaccount;publicMyTest(Accountaccount,Stringname){super(name);//设置thread的名称this.account=account;}@Overridepublicvoidrun(){//循环for(inti=0;i10;i++){if(i==6){//当i=6时,将name名称更改为当前的线程名account.setName(getName());}System.out.println(account.getName()+账户i的值:+i);}}}publicclassThreadLocalTest{publicstaticvoidmain(String[]args){Accountaccount=newAccount(初始名称);//启动两个线程,两人个线程共享同一个账户,即只有一个账户名./**虽然丙个线程共享同一个账户,即只有一个账户名.但由于账户名是ThradLocal类型的,所以每个线程都完全拥有各自的账户名副本,*因此在i=6以后,将看到两人个线程访问同一个账户时出现不同的账户名*/newMyTest(account,张三).start();newMyTest(account,李四).start();}}效果如下:4.关于ThreadLocal的几点说明1).ThreadLoca原理:ThreadLocalVariable(线程局部变量)的意思,其功能其实非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和D他线程的副本冲突,从线程的角度来看,就好像每个线程都完全拥有该变量一样.2).常用的方法:Tget():返回此线程局部变量中当前线程的值.voidremove():删除此线程局部变量中当前线程的值.voidset(Tvalue):设置此线程局部变量中当前线程副本中的值.3).ThradLocal和线程同步机制的区别:实现机制不同:和线程同步机制一样,都是为了解决多线程中,对同一变量的访问冲突,在普通的同步机制中,是通过对象加锁来实现多个线程对同一个变量的安全访问的.而ThreadLocal是将需要并发访问的资源复制多分,每个线程拥有一份资源,每个线程拥有自己的资源副本,从而也变没有必要对该变量进行同步了.面向问题的领域不同:ThreadLocal并不能替代同步机制,同步机制是为了同步多个线程对相同资源的并发访问,是多个线程之间进行通信的有效方式;而ThradLocal是为了隔离多个线程的数据共享,从根本上避免了多个线程之间对共享资源(变量)的竞争,也就不需要对多个线程进行同步了.4)何时使用?如果多个线程之间需要共享资源,以达到线程之间的通信功能,就使用同步机制.如果仅仅需要隔离多个线程之间的共享冲突,则可以使用ThreadLocal5.扩展---封装复杂数据对象packagecom.amos.concurrent;importjava.util.Random;/***@ClassName:ThreadLocalShareData*@Description:下面的例子用的是ThreadLocal对象将数据实现共享,封装复杂数据对象*@author:amosli*@email:hi_amos@outlook.com*@dateApr20,20146:19:02PM*/publicclassThreadLocalShareDataTest{publicstaticvoidmain(String[]args){for(inti=0;i3;i++){newThread(newRunnable(){publicvoidrun(){intdata=newRandom().nextInt();//给data设值,System.out.println(Thread.currentThread().getName()+setdata:+data);MyThreadData.getMyThreadData().setName(name+data);MyThreadData.getMyThreadData().setAge(data);newA().get();newB().get();}}).start();}}staticclassA{//这里A和B中的方法是一样的,可以只看一个publicvoidget(){MyThreadDatamyThreadData=MyThreadData.getMyThreadData();intdata=myThreadData.getAge();System.out.println(afromthread:+Thread.currentThread().getName()+age:+data+name:+myThreadData.getName());}}staticclassB{publicvoidget(){MyThreadDatamyThreadData=MyThreadData.getMyThreadData();intdata=myThreadData.getAge();System.out.println(bfromthread:+Thread.currentThread().getName()+age:+da