线程之间的通信
线程通信的目标实际上是线程直接能够互相发送信号,线程在接收到信号后执行特定的逻辑,信号可以是线程直接可见的变量;
也可以说线程直接有一些关联的操作,比如A,B两个线程,B线程需要等A线程执行完毕后在接着执行。
线程实现的方式:
1.使用自旋的方式
public class Demo {
private volatile int signal;
public void set (int value) {
this.signal = value;
}
public int get () {
return signal;
}
public static void main(String[] args) {
Demo d = new Demo();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("修改状态的线程执行...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
d.set(1);
System.out.println("状态值修改成功。。。");
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// 等待signal为1开始执行,否则不能执行
while(d.get() != 1) {
try {
Thread.sleep(1500);//休眠一会减少CPU的自旋消耗
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 当信号为1 的时候,执行代码
System.out.println("模拟代码的执行...");
}
}).start();
}
}
2.使用wait和notify,注意:使用的时候一定要放到同步synchrnoized代码块中使用。
public class Demo2 {
private volatile int signal;
public void set (int value) {
this.signal = value;
}
public int get () {
return signal;
}
public static void main(String[] args) {
Demo2 d = new Demo2();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (d) {
System.out.println("修改状态的线程执行...");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
d.set(1);
System.out.println("状态值修改成功。。。");
d.notify();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (d) {
// 等待signal为1开始执行,否则不能执行
while(d.get() != 1) {
try {
d.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 当信号为1 的时候,执行代码
System.out.println("模拟代码的执行...");
}
}
}).start();
}
}
3.注意:
wait方法会释放同步代码块synchronized的锁
notify方法会随机叫醒一个处于wait状态的线程,唤醒的线程会拿到锁
notifyAll叫醒所有的处于wait线程,争夺到时间片的线程只有一个
public class Target1 implements Runnable {
private Demo3 demo;
public Target1(Demo3 demo) {
this.demo = demo;
}
@Override
public void run() {
demo.set();
}
}
public class Target2 implements Runnable {
private Demo3 demo;
public Target2(Demo3 demo) {
this.demo = demo;
}
@Override
public void run() {
demo.get();
}
}
import java.util.concurrent.TimeUnit;
public class Demo3 {
private volatile int signal;
public synchronized void set () {
signal = 1;
notifyAll(); // notify方法会随机叫醒一个处于wait状态的线程
// notifyAll叫醒所有的处于wait线程,争夺到时间片的线程只有一个
System.out.println("叫醒线程叫醒之后休眠开始...");
try {
Thread.sleep(3000);//这里睡眠后方法的锁还没释放,只有等方法执行后,notifyAll通知的线程才会继续执行
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized int get () {
System.out.println(Thread.currentThread().getName() + " 方法执行了...");
if(signal != 1) {
try {
wait();
System.out.println("叫醒之后");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " 方法执行完毕...");
return signal;
}
public static void main(String[] args) {
Demo3 d = new Demo3();
Target1 t1 = new Target1(d);
Target2 t2 = new Target2(d);
new Thread(t2).start();
new Thread(t2).start();
new Thread(t2).start();
new Thread(t2).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(t1).start();
}
}
生产者消费者模式
//生产者
public class PushTarget implements Runnable {
private Tmall tmall;
public PushTarget(Tmall tmall) {
this.tmall = tmall;
}
@Override
public void run() {
while(true) {
tmall.push();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//消费者
public class TakeTarget implements Runnable {
private Tmall tmall;
public TakeTarget(Tmall tmall) {
this.tmall = tmall;
}
@Override
public void run() {
while(true) {
tmall.take();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
处理生产者和消费者数据
public class Tmall {
private int count;
public final int MAX_COUNT = 10;
public synchronized void push () {
while(count >= MAX_COUNT) {
try {
System.out.println(Thread.currentThread().getName() + " 库存数量达到上限,生产者停止生产。");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count ++;
System.out.println(Thread.currentThread().getName() + " 生产者生产,当前库存为:" + count);
notifyAll();//通知消费者去消费
}
public synchronized void take () {
while(count <= 0) {
try {
System.out.println(Thread.currentThread().getName() + " 库存数量为零,消费者等待。");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count --;
System.out.println(Thread.currentThread().getName() + " 消费者消费,当前库存为:" + count);
notifyAll();//叫醒生产者继续叫醒
}
}
测试类
public class Main {
public static void main(String[] args) {
Tmall tmall = new Tmall();
PushTarget p = new PushTarget(tmall);
TakeTarget t = new TakeTarget(tmall);
new Thread(p).start();
new Thread(p).start();
new Thread(p).start();
new Thread(p).start();
new Thread(p).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}
另外可以使用Condition实现生产者和消费者的例子
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Tmall2 {
private int count;
private Lock lock = new ReentrantLock();
Condition p = lock.newCondition();
Condition t = lock.newCondition();
public final int MAX_COUNT = 10;
public void push() {
lock.lock();
while (count >= MAX_COUNT) {
try {
System.out.println(Thread.currentThread().getName() + " 库存数量达到上限,生产者停止生产。");
p.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count++;
System.out.println(Thread.currentThread().getName() + " 生产者生产,当前库存为:" + count);
t.signal();
lock.unlock();
}
public void take() {
lock.lock();
while (count <= 0) {
try {
System.out.println(Thread.currentThread().getName() + " 库存数量为零,消费者等待。");
t.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
System.out.println(Thread.currentThread().getName() + " 消费者消费,当前库存为:" + count);
p.signal();
lock.unlock();
}
}
有关Condition的更多介绍请参照