一、进程间通信的方式
1. 管道和有名管道:管道可用于具有亲缘关系的父子进程间的
通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。
2. 信号(signal):
用于通知进程有某事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一致的。
3. 消息队列(message queue):消息队列是消息的链接表。比如生产者-消费者模式就用到该方式,生产者可以向队列中写东西,消费者从中拿取东西。
4. 共享内存(
shared memory)
:可以让多个进
程访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据得更
新。
5. 信号量(semaphore):可作为进程之间及同一种进程的不同线程之间得同步和互斥手段。
a.线程同步是指一个线程的执行依赖另一个线程的消息,当
它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
b.
线程互斥是指对于共享的进程系统资源的排它性。当有若干个线程使用某一共享资源时,任何时刻最多只允许一个线程去使用,其它则线程必须等待占用资源者释放该资源。
6. 套接字(socket):可用于网络中不同机器之
间的进程间通信。
二、线程间通信方式
1.
volatile
volatile有两大特性:
可见性:
对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。
有序性:
对volatile修饰的变量的读写操作前后加上各种特定的内存屏障来禁止指令重排序来保
障有序性
。
其中可见性就是可以让线程之间进行通信。那么volatile又是如何实现可见性的呢?
1.在硬件层面是通过lock前缀指令来锁定变量缓存行区域并写回主内存,
它可以让一个处理器的缓存回写到内存时导致其他处理器的缓存无效。
2.
JMM内存交互层面通过内存屏障,让它修饰的变量刷新缓存,重新从主存拿数据,由此保证volatile变量操作对多线程的可见性。
比如下面的代码就是通过volatile来实现线程间的通信的:
package com.spj.peng;
public class Visibility {
private static volatile boolean flag=true;
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
while (true){
if (flag){
System.out.println("on");
flag=false;
}
}
}
}).start();
new Thread(new Runnable() {
public void run() {
while (true){
if (!flag){
System.out.println("off");
flag=true;
}
}
}
}).start();
}
}
运行结果:
2.通过等待唤醒(等待通知)机制实现
等待唤醒机制可以基于wait和notify方法来实现,在一个线程内调用该线程锁对象的wait方法,
线程将进入等待队列进行等待直到被唤醒。
如下代码通过该方式实现:
package com.spj.peng;
public class WaitThread {
private static Object object=new Object();
private static boolean flag=true;
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
synchronized (object){
while (flag){
try {
System.out.println("Thread1 wait........");
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Thread1 wait end......");
}
}
}).start();
new Thread(new Runnable() {
public void run() {
synchronized (object){
if (flag){
object.notify();
System.out.println("notify......");
flag=false;
}
}
}
}).start();
}
}
还可以通过LockSupport中park()和unpark()来实现,线程调用park则等待“许可”,调用unpark则为指定线程提供“许可”。
package com.spj.peng;
import java.util.concurrent.locks.LockSupport;
public class LockSupportTest {
public static void main(String[] args) {
Thread parkThread = new Thread(new ParkThread());
parkThread.start();
System.out.println("唤醒parkThread");
LockSupport.unpark(parkThread);
}
static class ParkThread implements Runnable{
public void run() {
System.out.println("parkThread开始执行。。。");
LockSupport.park();
System.out.println("parkThread执行完成。。。");
}
}
}