接着学习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. 使用js在html文档的任意位置输出内容

    <script type="text/javascript">document.write('这里是内容');</script>

  2. KM算法萌新讲解篇

    KM算法   首先了解问题:也就是最大权值匹配: 二分图里,边带了权值,求整幅图里匹配最大/最小的权值 因为接触匈牙利算法的时候看的是找对象系列的博文,所以也自己写一发找对象的博文吧: 算法背景: 信 ...

  3. STLstack,queue

    今天一开始用C去摸栈和队列,差不多昨天早上也在摸,摸烦了就去搞DP然后DP也没搞好,就是很烦很烦!!!! 然后今天那些C的栈队列的步骤和名称熟的不要不要的,然而数据结构的c语言用指针,传递,简直麻烦, ...

  4. C#、Unity网络通信中基于字节码的自定义协议解码,C#版ByteBuffer

    http://www.oschina.net/code/snippet_42170_37516 C#.Unity基于字节的网络通信中字节码解析类,类似java中的ByteBuffer,不过这个实现是参 ...

  5. Apache与Tomcat的区别和联系

    经常在用apache和tomcat等这些服务器,可是总感觉还是不清楚他们之间有什么关系,在用tomcat的时候总出现apache,总感到迷惑,到底谁是主谁是次,因此特意在网上查询了一些这方面的资料,总 ...

  6. POP页面暂时不销毁

    摘要:我们经常使用的QQ空间,当我们短时间内两次进入页面的时候,页面是没有重新创建的,不光是缓存的数据,是整个页面都没有变.我们在开发中可能也会有这样的需求.开始的时候,想的思路是这样的:用定时器,将 ...

  7. Mysql优化配置

    Mysql配置优化 一.环境介绍 Mysql版本:5.5.27 二.优化内容 字段 介绍 推荐值 skip-locking 避免MySQL的外部锁定,减少出错几率增强稳定性 back_log MySQ ...

  8. hdu3642Get The Treasury

    链接 刚开始看n挺小,以为是二维的线段树,想了一会也没想到怎么解,之后看到z值非常小,想到可以直接枚举z,确定一个坐标,然后把三维转化为二维,把体积转化为面. 枚举z从-500到500,然后用面积并的 ...

  9. 实战:mysql写存储过程并定时调用

    有表:cap_meter_detail 字段:recordtime 情景:recordtime每半个小时记录一次,故一天会产生很很多数据,我们要做的是,每天00:00:00对cap_meter_det ...

  10. Java中的if-else语句——通过示例学习Java编程(7)

      作者:CHAITANYA SINGH 来源:https://www.koofun.com/pro/kfpostsdetail?kfpostsid=18 当我们需要根据一个条件执行一组语句时,我们需 ...