Java编程多线程之共享数据代码详解
本文主要总结线程共享数据的相关知识,主要包括两方面:一是某个线程内如何共享数据,保证各个线程的数据不交叉;一是多个线程间如何共享数据,保证数据的一致性。
线程范围内共享数据
自己实现的话,是定义一个Map,线程为键,数据为值,表中的每一项即是为每个线程准备的数据,这样在一个线程中数据是一致的。
例子
packagecom.iot.thread; importjava.util.HashMap; importjava.util.Map; importjava.util.Random; /** *Createdbybrianon2016/2/4. */ publicclassThreadScopeShareData{ //准备一个哈希表,为每个线程准备数据 privatestaticMapthreadData=newHashMap<>(); publicstaticvoidmain(String[]args){ for(inti=0;i<2;i++){ newThread( newRunnable(){ @Override publicvoidrun(){ intdata=newRandom().nextint(); threadData.put(Thread.currentThread(),data); System.out.println(Thread.currentThread()+"putdata:"+data); newA().get(); newB().get(); } } ).start(); } } staticclassA{ publicvoidget(){ intdata=threadData.get(Thread.currentThread()); System.out.println("Afrom"+Thread.currentThread()+"getdata"+data); } } staticclassB{ publicvoidget(){ intdata=threadData.get(Thread.currentThread()); System.out.println("Bfrom"+Thread.currentThread()+"getdata"+data); } } }
上述代码偶尔会报异常:
Exceptioninthread"Thread-0"java.lang.NullPointerException
atcom.iot.thread.ThreadScopeShareData$A.get(ThreadScopeShareData.java:29)
atcom.iot.thread.ThreadScopeShareData$1.run(ThreadScopeShareData.java:21)
atjava.lang.Thread.run(Thread.java:745)
具体原因还不知道
ThreadLocal类
API:
java.lang:ClassThreadLocal
- 单变量
使用ThreadLocal类型的对象代替上面的Map即可
- 多变量
定义一个对象来封装多个变量,然后在ThreadLocal中存储整个对象
多变量时,最好将ThreadLocal类放在数据类的内部,数据类采用单例模式,这样,新建对象和获取对象都会更方便,同时封装性更强。
示例代码:
packagecom.iot.thread; importjava.util.Random; /** *Createdbybrianon2016/2/4. */ publicclassThreadLocalTest{ privatestaticThreadLocalthreadInger=newThreadLocal<>(); publicstaticvoidmain(String[]args){ for(inti=0;i<2;i++){ newThread(newRunnable(){ @Override publicvoidrun(){ intdata=newRandom().nextint(100); threadInger.set(data); System.out.println(Thread.currentThread()+"putdata:"+data); MyThreadScopeData.getThreadInstance().setName(Thread.currentThread().toString()); MyThreadScopeData.getThreadInstance().setAge(data%10); newA().get(); newB().get(); } } ).start(); } } staticclassA{ publicvoidget(){ intdata=threadInger.get(); System.out.println("Afrom"+Thread.currentThread()+"getdata"+data); MyThreadScopeDatamyThreadScopeData=MyThreadScopeData.getThreadInstance(); System.out.println("Afrom"+myThreadScopeData); } } staticclassB{ publicvoidget(){ intdata=threadInger.get(); System.out.println("Bfrom"+Thread.currentThread()+"getdata"+data); MyThreadScopeDatamyThreadScopeData=MyThreadScopeData.getThreadInstance(); System.out.println("Bfrom"+myThreadScopeData); } } } /** *将多变量封装起来的数据类 *单例模式,内置ThreadLocal类型变量 */ classMyThreadScopeData{ privateMyThreadScopeData(){ } privatestaticThreadLocal data=newThreadLocal<>(); publicstaticMyThreadScopeDatagetThreadInstance(){ MyThreadScopeDatainstance=data.get(); if(instance==null){ instance=newMyThreadScopeData(); data.set(instance); } returninstance; } privateStringname; privateintage; publicStringgetName(){ returnname; } publicvoidsetName(Stringname){ this.name=name; } publicintgetAge(){ returnage; } publicvoidsetAge(intage){ this.age=age; } @Override publicStringtoString(){ StringreVal=super.toString()+"-{name,age}"+":{"+getName()+","+getAge()+"}"; returnreVal; } }
多线程访问共享数据
几种方式
- 线程执行代码相同,使用同一Runnable对象,Runnable对象中有共享数据
- 线程执行代码不同,将共享数据封装在另一对象中(操作数据的方法也在该对象完成),将这个对象逐一传递给各个Runnable对象。[本质:共享数据的对象作为参数传入Runnable对象]
- 线程执行代码不同,将Runnable对象作为某一个类的内部类,共享数据作为这个外部类的成员变量(操作数据的方法放在外部类)。[本质:不同内部类共享外部类数据]
- 结合上两种方式,将共享数据封装在另一对象中(操作数据的方法也在该对象完成),该对象作为这个外部类的成员变量,将Runnable对象作为内部类
最后一种方式的示例:
设计5个线程,其中三个线程每次对j增加1,另外两个线程对j每次减少1
packagecom.iot.thread; /** *Createdbybrianon2016/2/4. */ publicclassMutiThreadShareData{ privatestaticMutiShareDatamutiShareData=newMutiShareData(); publicstaticvoidmain(String[]args){ for(inti=0;i<3;i++){ newThread( newRunnable(){ @Override publicvoidrun(){ System.out.println(Thread.currentThread()+":{jfrom"+mutiShareData.getJ()+"+to:"+mutiShareData.increment()+"}"); } } ).start(); } for(inti=0;i<2;i++){ newThread( newRunnable(){ @Override publicvoidrun(){ System.out.println(Thread.currentThread()+":{jfrom"+mutiShareData.getJ()+"-to:"+mutiShareData.decrement()+"}"); } } ).start(); } } } /** *将共享数据封装在另一对象中(操作数据的方法也在该对象完成) */ classMutiShareData{ privateintj=0; publicsynchronizedintincrement(){ return++j; } publicsynchronizedintdecrement(){ return--j; } publicsynchronizedintgetJ(){ returnj; } publicsynchronizedvoidsetJ(intj){ this.j=j; } }
总结
以上就是本文关于Java编程多线程之共享数据代码详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!