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) 等待/通知的经典范式

概述:

等待方:

  1. 获取对象的锁
  2. 如果条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件
  3. 条件满足则执行对应的逻辑

通知方:

  1. 获得对象的锁
  2. 改变条件
  3. 通知所有等待在对象上的线程

用于线程之间的数据传输,而传输的媒介为内存

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对象为键、任意对象为值的存储结构

posted @ 2017-11-08 10:20  Free丶Will  阅读(157)  评论(0)    收藏  举报