线程并发库(通信,线程内共享数据)
2011-12-22 16:13
337 查看
通信
1. 等待在同步代码中调用锁对象的wait()方法,可以让当前线程等待
2. 通知唤醒
使用锁对象的notify()方法可以唤醒在该对象上等待的随机一个线程
使用锁对象的notifyAll()方法可以唤醒在该对象上等待的所有线程
示例:
创建三个线程,其中一个线程内部执行3次打印,第二个线程内部执行5次打印,第三个线程内部执行7次打印,如此交替执行10次。
public class NotifyTest { public static void main(String[] args) { final NotifyService service = new NotifyService(); //线程一 new Thread(new Runnable() { public void run() { for (int j = 0; j < 10; j++) service.print1(j); } }).start(); //线程二 new Thread(new Runnable() { public void run() { for (int j = 0; j < 10; j++) service.print2(j); } }).start(); //线程三 new Thread(new Runnable() { public void run() { for (int j = 0; j < 10; j++) service.print3(j); } }).start(); } } class NotifyService { private int flag = 1; // 当前轮到哪个 public synchronized void print1(int j) { while(flag != 1){ try { this.wait(); // 如果不该1, 就等待 } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < 3; i++){ System.out.println("线程1: " + j); } System.out.println(); flag = 2; // 1结束后轮到2 this.notifyAll(); // notify()唤醒随机一个, notifyAll()唤醒所有 } public synchronized void print2(int j) { while(flag != 2){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < 5; i++){ System.out.println("线程2: " + j); } System.out.println(); flag = 3; this.notifyAll(); } public synchronized void print3(int j) { while(flag != 3){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i < 7; i++){ System.out.println("线程3: " + j); } System.out.println(); flag = 1; this.notifyAll(); } }
线程范围内共享数据
1.应用场景在程序开发过程中我们经常需要在同一个线程中共享数据,例如我们常见的银行转账的案例,转入和转出是同一个线程上执行的两个方法,他们应该共享一个事务对象。
2.解决方案
1) 自定义Map
使用一个Key对象为Thread类型的Map用来保存数据。
在存储对象时将当前线程存为Key,数据存为Value。获取对象时使用当前线程对象即可获取到线程内部共享的数据。
采用Map来存储可能导致内存溢出
2) ThreadLocal
Java中为我们提供了一个和当前线程相关的容器ThreadLocal,实际上内部就是使用Map来进行存储的,只不过做了优化,在线程结束时会自动清空Map中的数据,以防止内存溢出。
当调用其set()方法时会将数据和当前线程绑定,调用get()方法时则是获取和当前线程绑定的数据。
一个ThreadLocal只能存储一个数据,如果有多个数据需要在线程范围内共享,可以创建多个ThreadLocal,或者将多个数据存入一个对象,将对象存入ThreadLocal。
使用Map在线程范围内共享数据:
private static Map<Thread, Integer> map = new HashMap<Thread, Integer>(); public static void main(String[] args) { new Thread(new Runnable() { public void run() { map.put(Thread.currentThread(), 5); System.out.println(Thread.currentThread().getName() + " set Data: " + 5); new A().get(); new B().get(); } }).start(); new Thread(new Runnable() { public void run() { map.put(Thread.currentThread(), 10); System.out.println(Thread.currentThread().getName() + " set Data: " + 10); new A().get(); new B().get(); } }).start(); } private static class A { public void get() { System.out.println(Thread.currentThread().getName() + " A.get Data: " + map.get(Thread.currentThread())); } } private static class B { public void get() { System.out.println(Thread.currentThread().getName() + " B.get Data: " + map.get(Thread.currentThread())); } }使用ThreadLocal在线程范围内共享数据:
// key值固定为Thread的一个Map容器, 存储对象的时候, 用当前线程作为key, 获取的时候也是当前线程作为key // 在线程销毁的时候, 容器中的记录会自动删除 private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(); public static void main(String[] args) { new Thread(new Runnable() { public void run() { threadLocal.set(5); // 用当前线程作为key存储数据 System.out.println(Thread.currentThread().getName() + " set Data: " + 5); new A().get(); new B().get(); } }).start(); new Thread(new Runnable() { public void run() { threadLocal.set(10); System.out.println(Thread.currentThread().getName() + " set Data: " + 10); new A().get(); new B().get(); } }).start(); } private static class A { public void get() { // 用当前线程作为key获取数据 System.out.println(Thread.currentThread().getName() + " A.get Data: " + threadLocal.get()); } } private static class B { public void get() { System.out.println(Thread.currentThread().getName() + " B.get Data: " + threadLocal.get()); } }使用ThreadLocal在线程范围内共享多个数据:
public static void main(String[] args) { new Thread(new Runnable() { public void run() { SharedData data = SharedData.getSharedData(); // 获取当前线程的共享数据 data.setName("张三"); data.setAge(19); System.out.println(Thread.currentThread().getName() + " set Data: " + data); new A().get(); new B().get(); } }).start(); new Thread(new Runnable() { public void run() { SharedData data = SharedData.getSharedData(); data.setName("李四"); data.setAge(20); System.out.println(Thread.currentThread().getName() + " set Data: " + data); new A().get(); new B().get(); } }).start(); } private static class A { public void get() { System.out.println(Thread.currentThread().getName() + " A.get Data: " + SharedData.getSharedData()); } } private static class B { public void get() { System.out.println(Thread.currentThread().getName() + " B.get Data: " + SharedData.getSharedData()); } } } class SharedData { // 该类所有实例共享 private static ThreadLocal<SharedData> threadLocal = new ThreadLocal<SharedData>(); // 数据 private String name; private int age; private SharedData(){ } public static SharedData getSharedData(){ SharedData data = threadLocal.get(); if(data == null){ data = new SharedData(); threadLocal.set(data); } return data; } public String toString() { return "SharedData(" + name + ", " + age + ")"; } 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; }
相关文章推荐
- 线程间的通信 共享数据安全问题
- 多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify())
- 专业课程设计之客户与服务器程序的同步与通信机制的设计(三)数据共享和线程
- Python 进程线程之间通信方式(2.1,共享数据实现进程之间通信)
- 线程间无需特别的手段进行通信,因为线程间可以共享数据结构,也就是一个全局变量可以被两个线程同时使用,不过要注意的是线程间需要做好同步。
- Java笔记1 : 在生产者消费者模式中,线程通信与共享数据,死锁问题与解决办法
- Python 进程线程之间通信方式(2,共享数据实现进程之间通信)
- 进程间通信机制(管道、信号、共享内存/信号量/消息队列)、线程间通信机制(互斥锁、条件变量、posix匿名信号量)
- Java高并发编程:线程范围内共享数据
- 线程共享的环境包括:进程代码段、进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。 进程拥有这
- Java死锁和线程范围内共享数据
- 4、线程范围内的数据共享之ThreadLocal
- 多线程(三) 实现线程范围内模块之间共享数据及线程间数据独立(ThreadLocal)
- 线程系列03,多线程共享数据,多线程不共享数据
- 运行时数据区和线程私有/共享
- Java多线程共享数据、同步、通信
- Java并发库(五、六、七):线程范围内共享数据、ThreadLocal、共享数据的三种方法
- 详解 Qt 线程间共享数据(用信号槽方式)
- 进程间通信机制(管道、信号、共享内存/信号量/消息队列)、线程间通信机制(互斥锁、条件变量、posix匿名信号量)
- 使用ACE互斥,同步线程共享的数据资源