java并发_线程通信
三.线程间通信
通信机制分为两种:共享内存机制和消息通信机制。volatile 和synchronized 是共享内存机制的实现方式,同时也要考虑通信的及时性和开销问题,等待/通知机制则保证了通信双方“高效沟通”的一种方式。管道输入/输出流则是消息通信机制的实现方式。线程间的执行顺序是通过Thread.join()来实现的。
1)volatile和synchronized关键字
概述:线程间通信在JAVA内存模型基础上的实现机制,是通过volatile,synchronized来体现的。
关键字volatile可以用来修饰字段(成员变量),就是告知程序任何对该变量的访问均需要
从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问
的可见性。
关键字synchronized可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程
在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性
和排他性。
volatile和synchronized的比较:
①volatile轻量级,只能修饰变量。synchronized重量级,还可修饰方法
②volatile只能保证数据的可见性,不能用来同步,因为多个线程并发访问volatile修饰的变量不会阻塞。
synchronized不仅保证可见性,而且还保证原子性,因为,只有获得了锁的线程才能进入临界区,从而保证临界区中的所有语句都全部执行。多个线程争抢synchronized锁对象时,会出现阻塞。
底层实现原理:对象的监视器
2)等待/通知机制
解决生产者,消费者消息通知及时性和难以降低开销的矛盾
等待/通知机制:是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B
调用了对象O的notify()或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而
执行后续操作。上述两个线程通过对象O来完成交互,而对象上的wait()和notify/notifyAll()的
关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。
3) 等待/通知的经典范式
概述:
等待方:
- 获取对象的锁
- 如果条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件
- 条件满足则执行对应的逻辑
通知方:
- 获得对象的锁
- 改变条件
- 通知所有等待在对象上的线程
用于线程之间的数据传输,而传输的媒介为内存
4)管道输入\输出流
/**
* 管道输入/输出流
* @author uns
*
*/
public class Piped {
public static void main(String[] args) {
PipedReader reader = new PipedReader();
PipedWriter writer = new PipedWriter();
try {
writer.connect(reader);//输入流和输出流进行连接
Thread thread = new Thread(new Print(reader),"PrintThread");
thread.start();
int received = 0;
while ((received = System.in.read()) !=-1) {
System.out.println((char)received);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static class Print implements Runnable {
private PipedReader reader;
public Print(PipedReader reader) {
this.reader = reader;
}
public void run() {
int received = 0;
try {
while ((received = reader.read()) !=-1) {
System.out.println((char)received);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
用来维护线程的执行先后关系
5)Thread.join()
含义:thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。
启动10个线程,把上一个线程加入的到当前线程,执行Thread.join()方法,上一个线程执行完,再执行当前线程。
/**
* Thread.join()方法
* 维护线程执行顺序
* @author LeeRujun
*
*/
public class Join {
public static void main(String[] args) {
Thread thread = Thread.currentThread();//上一个线程
for (int i = 0; i < 10; i++) {
Thread thread2 = new Thread(new Domain(thread),String.valueOf(i));
thread2.start();
thread =thread2;
}
try {
TimeUnit.SECONDS.sleep(5);
System.out.println(Thread.currentThread().getName());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static class Domain implements Runnable{
private Thread thread;
public Domain(Thread thread) {
this.thread = thread;
}
public void run() {
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
线程之间数据存储结构
6)ThreadLocal
ThreadLocal,即线程变量,是一个以ThreadLocal对象为键、任意对象为值的存储结构
作者:LeeRuJun
出处:http://www.cnblogs.com/free-will/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

浙公网安备 33010602011771号