接着学习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. Lightoj1002 【搜索】

    题意: 两两之间的点的花费就是:从A点到B的一条路上某段的最大权值:给一个起点,求到各起点的最小花费. 思路: 一开始的思路: n不是才500,我先建个图,然后DFS一下,不对,是2500: 如果直接 ...

  2. web框架原理,http 协议

    目录 web框架原理 web框架是什么东西 执行代码用浏览器访问一下 输出结果 http 协议 http 协议简介 http 协议概述 http 工作原理 http请求方法 http 状态码 url介 ...

  3. nmon性能监控工具学习

    nmon在AIX环境上,是一款很出名的系统性能监控工具,其实它除了可以运行在AIX,还可以在Linux环境下编译.使用. 源码下载地址: http://nmon.sourceforge.net/pmw ...

  4. AngularJS - 入门小Demo

    AngularJS四大特效 MVC模式.模块化设计.自动化双向数据绑定.依赖注入 如果了解了后端开发知识,想必对这些词汇不会陌生,AngularJS融合了后端开发的一些思想,虽然身为前端框架,但与jQ ...

  5. CSS 两边是线 中间是文字的效果

    刚开始做的时候 想了一下 这个是怎么做出来的,后来在网上看到有个类似的效果,研究一下 <!DOCTYPE html> <html lang="en"> &l ...

  6. ZROI #364. 【2018普转提day18专题】嘤嘤嘤

    ZROI #364. [2018普转提day18专题]嘤嘤嘤 直接贴代码 具体见注释 #include<stdio.h> #include<cstring> #include& ...

  7. Codeforces Round #542(Div. 2) B.Two Cakes

    链接:https://codeforces.com/contest/1130/problem/B 题意: 给定n和 2 * n个数,表示i位置卖ai层蛋糕, 有两个人在1号,必须严格按照1-n的顺序买 ...

  8. [已读]Nodejs高级编程

    封面太让人想吐槽了,真的很像<javascript高级程序设计>有木有 内容我觉得还不错,流畅,见过的nodejs书籍中最详细的一本.很多书会把express及使用案例作为重点,但是它不是 ...

  9. 《javascript设计模式》笔记之第四章:继承

    一:首先,一个简单的继承实例: 首先是创建一个父类Person: function Person(name) { this.name = name; } Person.prototype.getNam ...

  10. Oracle 修改密码(忘记登录密码,用户System)

    1.修改计算机环境变量,把oracle服务端路径放在最前面 2.输入cmd 3.输入命令:sysplus /nolog SQL>conn sys/syspwd as sysdba SQL> ...