线程通信
线程通信是什么
线程通信的目标是使线程间能够互相发送信号。另一方面,线程通信使线程能够等待其他线程的信号。
例如,线程B可以等待线程A的一个信号,这个信号会通知线程B数据已经准备好了。
wait()/notify()/notifyAll()
必须在synchronized同步代码块中使用
一个线程一旦调用了任意对象的wait()方法,就会变为非运行状态,直到另一个线程调用了同一个对象的notify()方法。为了调用wait()或者notify(),线程必须先获得那个对象的锁。也就是说,线程必须在同步块里调用wait()或者notify()。
例子:写2个线程,其中一个线程打印1-52,另一个线程打印A-Z,打印顺序应该是12A34B56C……5152Z
class Print{
int index = 1;
public synchronized void printint(int i){
while (index % 3 == 0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print(i);
index++;
notifyAll();
}
public synchronized void printchar(char c){
while (index % 3 != 0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print(c);
index++;
notifyAll();
}
}
public class Demo {
public static void main(String[] args) {
Print print = new Print();
new Thread(){
@Override
public void run() {
for (int i = 1; i <=52 ; i++) {
print1.printint(i);
}
}
}.start();
new Thread(){
@Override
public void run() {
for (char c = 'A';c <= 'Z';c++){
print1.printchar(c);
}
}
}.start();
}
}
await/signal/signalAll
当使用Lock来保证线程同步时,需使用Condition对象来使线程保持协调。Condition实例被绑定在一个Lock的对象上,使用Lock对象的方法newCondition()获取Condition的实例。Condition提供了下面三种方法,来协调不同线程的同步:
-
await():导致当前线程等待,直到其他线程调用该Condition的signal()或signalAll()方法唤醒该线程。
-
signal():唤醒在此Lock对象上等待的单个线程。
-
signalAll():唤醒在此Lock对象上等待的所有线程。
例子:写2个线程,其中一个线程打印1-52,另一个线程打印A-Z,打印顺序应该是12A34B56C……5152Z
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Print{
private final Lock lock = new ReentrantLock();
private final Condition intCon = lock.newCondition();
private final Condition charCon = lock.newCondition();
int index = 1;
public void pinttInt(int i){
try{
lock.lock();
while (index % 3 == 0){
intCon.await();
}
System.out.print(i);
index++;
charCon.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printChar(char c){
try{
lock.lock();
while (index % 3 != 0){
charCon.await();
}
System.out.print(c);
index++;
intCon.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public class Demo {
public static void main(String[] args) {
Print print = new Print();
new Thread(){
@Override
public void run() {
for (int i = 1; i <= 52 ; i++) {
print.pinttInt(i);
}
}
}.start();
new Thread(){
@Override
public void run() {
for (char c = 'A';c <= 'Z';c++) {
print.printChar(c);
}
}
}.start();
}
}
生产者消费者模型
一种重要的模型,基于等待/通知机制。生产者/消费者模型描述的是有一块缓冲区作为仓库,生产者可将产品放入仓库,消费者可以从仓库中取出产品,生产者/消费者模型关注的是以下几个点:
1、生产者生产的时候消费者不能消费
2、消费者消费的时候生产者不能生产
3、缓冲区空时消费者不能消费
4、缓冲区满时生产者不能生产
await/signal/signalAll实现
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Blocking<E>{
private final Lock lock = new ReentrantLock();
//生产
private final Condition pro = lock.newCondition();
//消费
private final Condition con = lock.newCondition();
private final LinkedList<E> queue = new LinkedList<>();
private static int max;
public Blocking(int max) {
this.max = max;
}
public void put(E value){
try{
lock.lock();
while (queue.size() >= max){
System.out.println(Thread.currentThread().getName()+": queue is full!!!");
pro.await();
}
System.out.println(Thread.currentThread().getName()+" has been producting a new value: "+value);
queue.addLast(value);
con.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void take(){
try{
lock.lock();
while (queue.isEmpty()){
System.out.println(Thread.currentThread().getName()+": queue is empty!!!");
con.await();
}
E result = queue.removeFirst();
pro.signalAll();
System.out.println(Thread.currentThread().getName()+" has been concuming a new value: "+result);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
public class Producer {
public static void main(String[] args) {
Blocking<Integer> queue = new Blocking<>(5);
new Thread("Producer"){
@Override
public void run() {
while(true){
queue.put((int)(1+Math.random() * 1000));
}
}
}.start();
new Thread("Consumer"){
@Override
public void run() {
while(true){
queue.take();
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}
wait/notify/notifyAll实现
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
class BlockingQueue1<E>{
private final LinkedList<E> queue = new LinkedList<>();
private static final int DEFAULT_MAX = 5;
private static int max;
public BlockingQueue(){
this(DEFAULT_MAX);
}
public BlockingQueue1(int max){
this.max = max;
}
public void put(E value){
synchronized (queue){
//判断当前队列是否满
while(queue.size() >= max){
System.out.println(Thread.currentThread().getName()+": queue is full!!!");
//满 则将当前生产者线程阻塞 wait
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//不满 则添加数据到队列中
System.out.println(Thread.currentThread().getName()+" has been producting a new value: "+value);
queue.addLast(value);
//唤醒阻塞的消费者线程 notify
queue.notifyAll();
}
}
public E take(){
synchronized (queue){
//判断当前队列是否空
while(queue.isEmpty()){
System.out.println(Thread.currentThread().getName()+": queue is empty!!!");
try {
//空 则将当前消费者线程阻塞 wait
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//不空 则消费数据
E result = queue.removeFirst();
//唤醒阻塞的生产者线程 notify
queue.notifyAll();
System.out.println(Thread.currentThread().getName()+" has been concuming a new value: "+result);
return result;
}
}
}
public class ProducerAndConsumer {
public static void main(String[] args) {
BlockingQueue1<Integer> queue = new BlockingQueue1<>(5);
new Thread("Producer"){
@Override
public void run() {
while(true){
queue.put((int)(1+Math.random() * 1000));
}
}
}.start();
new Thread("Consumer"){
@Override
public void run() {
while(true){
queue.take();
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
}