Java中的线程--线程范围内共享数据
接着学习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中的线程--线程范围内共享数据的更多相关文章
- Java并发基础06. 线程范围内共享数据
假设现在有个公共的变量 data,有不同的线程都可以去操作它,如果在不同的线程对 data 操作完成后再去取这个 data,那么肯定会出现线程间的数据混乱问题,因为 A 线程在取 data 数据前可能 ...
- Java中的守护线程 & 非守护线程(简介)
Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...
- Java中如何创建线程
Java中如何创建线程 两种方式:1)继承Thread类:2)实现Runnable接口. 1.继承Thread类 继承Thread类,重写run方法,在run方法中定义需要执行的任务. class M ...
- 实现java 中 list集合中有几十万条数据,每100条为一组取出
解决"java 中 list集合中有几十万条数据,每100条为一组取出来如何实现,求代码!!!"的问题. 具体解决方案如下: /** * 实现java 中 list集合中有几十万条 ...
- 【转】asp.net中利用session对象传递、共享数据[session用法]
来自:http://blog.unvs.cn/archives/session-transfer-method.html 下面介绍Asp.net中利用session对象传递.共享数据用法: 1.传递值 ...
- asp.net中利用session对象传递、共享数据[session用法]
下面介绍Asp.net中利用session对象传递.共享数据用法: 1.传递值: 首先定义将一个文本值或单独一个值赋予session,如下: session[“name”]=textbox1.text ...
- Java线程与并发库高级应用-线程范围内共享数据ThreadLocal类
1.线程范围内共享变量 1.1 前奏: 使用一个Map来实现线程范围内共享变量 public class ThreadScopeShareData { static Map<Thread, In ...
- ThreadLocal,Java中特殊的线程绑定机制
在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个 ...
- Java-ThreadLocal,Java中特殊的线程绑定机制
在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个 ...
随机推荐
- css控制页面文字不能被选中user-select:none;
现象:html中可能有些地方不想让用户复制文字,或是用a标签做了个点击按钮,点快的时候文字会被选中,很丑,这个时候可以使用下面的方案禁止文字选中. 原因:鼠标点快了文字会被选中. 解决方案:不同的浏览 ...
- 学习RESTFul架构
一.RESTFul介绍 1.一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件.它主要用于客户端和服务器交互类的软件.基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机 ...
- Oculus Rift, HTC Vive, SONY PSVR的全面对比
http://blog.csdn.net/xoyojank/article/details/50927572 这次有幸参加了GDC 2016, 终于把三大设备体验了个遍, 也试玩了很多不错的VR游戏. ...
- 51nod1640(kruscal)
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1640 题意:中文题诶- 思路:kruscal 题目要求是在边权 ...
- typescript学习笔记(一)----基础类型
1.使用typescript前第一个操作就是全局配置typescript环境 ---------------npm install -g typescript 2.typescript(以下称为ts, ...
- kuangbin大佬的高斯消元模板
dalao解释的博客 #include <bits/stdc++.h> using namespace std; ; int a[MAXN][MAXN];//增广矩阵 int x[MAXN ...
- python之文件路径截取 & endswith()
文件路径截取: >>> import os >>> path = '/etc/singfor/passwd/sunny/test.log' >>> ...
- Flask (四) 模型进阶
模型进阶 多对多关联 用户收藏电影,一个用户可以收藏多部电影, 一部电影可以被不同的用户收藏, 是一个多对多关系. # 中间表(不是模型) collects = db.Table('collect ...
- CF #541div2 F
题目本质:并查集的链式合并 解决方法1: 类似哈夫曼树,叶节点们为真点,其余造一些虚的父节点,使得dfs这棵树的时候,先进行并查合并的点一定是兄弟节点因而紧挨着被输出,巧妙达到了效果. #pragma ...
- bryce1010专题训练——LCA
1.Targan算法(离线) http://poj.org/problem?id=1470 /*伪代码 Tarjan(u)//marge和find为并查集合并函数和查找函数 { for each(u, ...