多线程与并发-线程间通信
概述:
多线程之间通信一般有这样几种方法:
- 通过共享对象实现通信
- wait/notify机制
- Condition接口,await/signal机制
- 消息队列,socket编程等网络通信
wait/notify机制
基础
前提:多个线程使用用一把锁,在使用wait(),notify(),notifyAll()之前要先获取当前对象的锁。
- wait():运行至wait处时立刻阻塞当前线程,并释放锁。当被通知唤醒后开始竞争锁,如果获取到锁在继续向下执行。
- notify():运行至notify处时立刻发送通知唤醒一个等待线程,但需要等到同步块运行结束之后才释放锁。
- notifyAll():唤醒所有等待线程。
其余方法 - wait(long millis),时间到了相当于被通知,自动唤醒
实现
以生产者消费者为例吧
单一缓存空间
public class A {
private static String value;
class MyService{
private final String lock = new String("");
private int i=0;
public void produce(){
synchronized (lock) {
try {
if(A.value!=null) {
lock.wait();
}
A.value=" value = "+ i++;
System.out.println("生产 :"+A.value);
Thread.sleep(1000);
lock.notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void consume(){
synchronized(lock) {
try {
if(A.value==null) {
lock.wait();
}
System.out.println("消费 :"+A.value);
A.value=null;
Thread.sleep(1000);
lock.notify();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
class ProduceThread extends Thread{
private MyService service;
ProduceThread(MyService service){
this.service=service;
}
@Override
public void run() {
while(true) {
service.produce();
}
}
}
class ConsumerThread extends Thread{
private MyService service;
ConsumerThread(MyService service){
this.service=service;
}
@Override
public void run() {
while(true) {
service.consume();
}
}
}
public static void main(String[] args) {
A a = new A();
MyService service = a.new MyService();
a.new ProduceThread(service).start();
a.new ConsumerThread(service).start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.exit(0);
}
}
缓存空间大于1
public class A {
private static LinkedList<String> values = new LinkedList<>();
private static final int SIZE = 5;
class MyService{
private final String lock = new String("");
private int i=0;
public void produce(){
synchronized (lock) {
try {
while(A.values.size()==A.SIZE) {
lock.wait();
}
String value =" value = "+ i++;
A.values.add(value);
long id = Thread.currentThread().getId();
System.out.printf("Thread %d 生产 :%s\n",id,value);
lock.notifyAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void consume(){
synchronized(lock) {
try {
while(A.values.size()==0) {
lock.wait();
}
String value = A.values.poll();
long id = Thread.currentThread().getId();
System.out.printf("Thread %d 消费 :%s\n",id,value);
lock.notifyAll();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ProduceThread extends Thread{
private MyService service;
ProduceThread(MyService service){
this.service=service;
}
@Override
public void run() {
while(true) {
service.produce();
}
}
}
class ConsumerThread extends Thread{
private MyService service;
ConsumerThread(MyService service){
this.service=service;
}
@Override
public void run() {
while(true) {
service.consume();
}
}
}
public static void main(String[] args) {
A a = new A();
MyService service = a.new MyService();
List<Thread> threads = new ArrayList<>();
for(int i=0;i<10;i++) {
threads.add(a.new ProduceThread(service));
threads.add(a.new ConsumerThread(service));
}
for(Thread thread : threads) {
thread.start();
}
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.exit(0);
}
}
为不让单一线程完成所有生产或消费在外面休眠一定时间。
使用while与notifyAll避免假死现象出现(所有线程处于等待状态),原因:notify只通知一个线程,可能是同类型线程而非异构线程(生产者->消费者,消费者->生产者)
同时也可以通过while避免等待条件发生改变,避免过早通知问题
Condition
await/signal机制
await()与wait()类似
signal()与notify类似,但通知的是同一个Condition
一个Lock对象可以创建多个Condition条件。实现部分通知功能。