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(){
}
privatestaticThreadLocaldata=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编程多线程之共享数据代码详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!