接着学习Java中的线程,线程范围内的共享数据!

一、线程范围内的数据共享定义

对于相同的程序代码,多个模块在同一个线程中共享一份数据,而在另外线程中运行时又共享另外一份数据。

共享数据中存在的问题,代码如下:

 // A 和 B共享数据data,但是在这种情况下 会存在问题
public class ThreadScopeShareData { private static int data = 0; public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
data = new Random().nextInt();
System.out.println(Thread.currentThread().getName() + "has put data " + data);
new A().get();
new B().get();
}
}).start();
}
} static class A {
public void get() {
System.out.println("A from " + Thread.currentThread().getName() + "has put data " + data);
}
} static class B {
public void get() {
System.out.println("B from " + Thread.currentThread().getName() + "has put data " + data);
}
} }

运行结果如下:(好像是有点乱七八糟的感觉)

 Thread-3has put data 1233171571
Thread-7has put data -1796246182
Thread-1has put data -609826403
A from Thread-3has put data 1961867182
A from Thread-1has put data 1961867182
Thread-8has put data 2116621494
A from Thread-8has put data 1961867182
Thread-5has put data -609826403
A from Thread-5has put data 1961867182
A from Thread-7has put data 1961867182
B from Thread-7has put data 1961867182
B from Thread-5has put data 1961867182
Thread-6has put data -609826403
A from Thread-6has put data 1961867182
B from Thread-6has put data 1961867182
Thread-0has put data 1233171571
A from Thread-0has put data 1961867182
B from Thread-0has put data 1961867182
Thread-9has put data 1961867182
A from Thread-9has put data 1961867182
B from Thread-9has put data 1961867182
B from Thread-1has put data 1961867182
Thread-2has put data 1233171571
Thread-4has put data 1233171571
A from Thread-4has put data 1961867182
B from Thread-4has put data 1961867182
B from Thread-8has put data 1961867182
B from Thread-3has put data 1961867182
A from Thread-2has put data 1961867182
B from Thread-2has put data 1961867182

解决方案如下,用线程范围内的变量,当然这个是比较粗糙的解决方案,代码如下:

 public class ThreadScopeShareData {

     private static int data = 0;
// 这个用来存放当前线程内的共享数据
private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>(); public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName() + "has put data " + data);
threadData.put(Thread.currentThread(), data);
new A().get();
new B().get();
}
}).start();
}
} static class A {
public void get() {
int data = threadData.get(Thread.currentThread());
System.out.println("A from " + Thread.currentThread().getName() + "has put data " + data);
}
} static class B {
public void get() {
int data = threadData.get(Thread.currentThread());
System.out.println("B from " + Thread.currentThread().getName() + "has put data " + data);
}
} }

二、JDK中解决线程共享数据(ThreadLocal)

优化解决方法,更加优雅的代码,更加人性化的解决方法,使得用户用起来更加方便,封装到ThreadLocal中,并且得保证同一个线程,所得到的的是同一份数据!

改造之后的实体对象,代码如下:

 // 改造之后的实体类,封装创建方法,并且封装ThreadLocal,来保证同一个线程得到的同一个对象
public class MyThreadScopeData { private String name;
private int age;
//private static MyThreadScopeData instance = null;
private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>(); private MyThreadScopeData() { } public static /* synchronized */ MyThreadScopeData getThreadInstance() {
MyThreadScopeData instance = map.get();
if(instance == null) {
instance = new MyThreadScopeData();
map.set(instance);
}
return instance;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} }

测试类中代码如下:

 public class ThreadLocalTest {

     private static ThreadLocal<Integer> x = new ThreadLocal<Integer>();
private static ThreadLocal<MyThreadScopeData> myThreadLocal = new ThreadLocal<MyThreadScopeData>(); public static void main(String[] args) {
// 相当于创建了10个线程
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
int data = new Random().nextInt();
System.out.println(Thread.currentThread().getName() + "has put data " + data);
// MyThreadScopeData myData = new MyThreadScopeData();
// myData.setName("name" + data);
// myData.setAge(data);
// myThreadLocal.set(myData); MyThreadScopeData.getThreadInstance().setName("name" + data);
MyThreadScopeData.getThreadInstance().setAge(data);
// 存放的是与当前线程相关的数据
x.set(data); new A().get();
new B().get();
}
}).start();
}
} static class A {
public void get() {
int data = x.get();
System.out.println("A from " + Thread.currentThread().getName() + "has get data " + data); // MyThreadScopeData myData = myThreadLocal.get();
// System.out.println("A from " + Thread.currentThread().getName() + "has getMyData " + myData.getName() + ","
// + myData.getAge()); MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("A from " + Thread.currentThread().getName() + "has getMyData " + myData.getName() + ","
+ myData.getAge());
}
} static class B {
public void get() {
int data = x.get();
System.out.println("B from " + Thread.currentThread().getName() + "has get data " + data); // MyThreadScopeData myData = myThreadLocal.get();
// System.out.println("B from " + Thread.currentThread().getName() + "has getMyData " + myData.getName() + ","
// + myData.getAge()); MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();
System.out.println("B from " + Thread.currentThread().getName() + "has getMyData " + myData.getName() + ","
+ myData.getAge());
}
}
}

总结:这个线程范围内的数据共享问题,解决的方法中用到了单例模式中的设计思想,但是区别的地方是加了一步将数据存放到ThreadLocal 中,实现数据的共享!

三、多线程访问共享数据和线程的方式

也是线程间数据共享的问题,只不过这个是以实战的角度来探索线程共享间数据的同步问题,主要学的是这种解决实际问题的能力,看看代码:

 public class MultiThreadShareData {

     public static void main(String[] args) {
final ShareData1 data1 = new ShareData1(); new Thread(new Runnable() {
@Override
public void run() {
data1.decrement();
}
}).start(); new Thread(new Runnable() {
@Override
public void run() {
data1.increment();
}
}).start();
} static class ShareData1 /* implements Runnable */ { private int j = 0;
private int count = 100; public synchronized void increment() {
j++;
} public synchronized void decrement() {
j--;
} /*
* @Override public void run() { while (true) { count--; } }
*/
} }

Java中的线程--线程范围内共享数据的更多相关文章

  1. Java并发基础06. 线程范围内共享数据

    假设现在有个公共的变量 data,有不同的线程都可以去操作它,如果在不同的线程对 data 操作完成后再去取这个 data,那么肯定会出现线程间的数据混乱问题,因为 A 线程在取 data 数据前可能 ...

  2. Java中的守护线程 & 非守护线程(简介)

    Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...

  3. Java中如何创建线程

    Java中如何创建线程 两种方式:1)继承Thread类:2)实现Runnable接口. 1.继承Thread类 继承Thread类,重写run方法,在run方法中定义需要执行的任务. class M ...

  4. 实现java 中 list集合中有几十万条数据,每100条为一组取出

    解决"java 中 list集合中有几十万条数据,每100条为一组取出来如何实现,求代码!!!"的问题. 具体解决方案如下: /** * 实现java 中 list集合中有几十万条 ...

  5. 【转】asp.net中利用session对象传递、共享数据[session用法]

    来自:http://blog.unvs.cn/archives/session-transfer-method.html 下面介绍Asp.net中利用session对象传递.共享数据用法: 1.传递值 ...

  6. asp.net中利用session对象传递、共享数据[session用法]

    下面介绍Asp.net中利用session对象传递.共享数据用法: 1.传递值: 首先定义将一个文本值或单独一个值赋予session,如下: session[“name”]=textbox1.text ...

  7. Java线程与并发库高级应用-线程范围内共享数据ThreadLocal类

    1.线程范围内共享变量 1.1 前奏: 使用一个Map来实现线程范围内共享变量 public class ThreadScopeShareData { static Map<Thread, In ...

  8. ThreadLocal,Java中特殊的线程绑定机制

    在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个 ...

  9. Java-ThreadLocal,Java中特殊的线程绑定机制

    在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个 ...

随机推荐

  1. Lightoj 1098【数学/玄学】

    题意: 对于每个数求除1和本身的约数和,然后求前n个数的所有这种约数的和: 思路: 首先可以知道对于约数考虑就好了, 对于1-n的约数,n/2-1(减1是因为2不算啊)就是约数为2出现过的次数 如果n ...

  2. 51nod1414【思维】

    思路: 直接可以枚举1-n,如果枚举到是n的约数i,那么暴力枚举起点,其余点用i累加就一定是正多边形.复杂度是(n*n的公约数个数(最多80)): const int N=2e4+10; int a[ ...

  3. 3D max模型导入unity 3D中注意事项

    一.单位,比例统一   在建模型前先设置好单位,在同一场景中会用到的模型的单位设置必须一样,模型与模型之间的比例要正确,和程序的导入单位一致,即便到程序需要缩放也可以统一调整缩放比例.统一单位为米. ...

  4. Java相关书籍阅读

  5. Hexo搭建博客教程(2) - 博客的简单个性化配置

    本章主要讲博客的个性化,譬如站点的基本配置(语言.头像.站点图标等).安装新的Hexo主题(NexT主题)以及主题的配置. 1. 修改站点配置 打开站点配置文件 ,找到: # Site title: ...

  6. $.ajax()与vue结合获取数据并渲染

    html: <div id="app1"> <ul> <li v-for="item in datas"> <div ...

  7. __contains__, __len__,__reversed__

    __contains__():当使用in,not in 对象的时候 调用(not in 是在in完成后再取反,实际上还是in操作) class A(object): def __init__(self ...

  8. Hadoop启动datanode失败,clusterId有问题

    问题: 搭建伪Hadoop集群的时候,运行命令: hdfs namenode -format 格式化或者说初始化namenode. 然后用命令: start-dfs.sh 来启动hdfs时,jps发现 ...

  9. vue项目打包后文本溢出代码消失问题

    补充 https://www.cnblogs.com/richard1015/p/8526988.html vue webpack 打包编译-webkit-box-orient: vertical 后 ...

  10. nodejs 学习(1) http与fs

    var http=require("http"), fs=require('fs'); var server=http.createServer(function(req,res) ...