线程通信的三种方式
同步
这里讲的同步是synchronized 关键字来实现线程间的通信,我们用代码来示范一下。
class Obj{
int count = 0;
public synchronized void add(){
//do something
count++;
}
public synchronized void del(){
//do something
count--;
}
}
public class Demo4 {
static Obj obj = new Obj();
public static void main(String[] args) {
//线程1
new Thread(new Runnable(){
public void run() {
for(int i = 0;i < 10;i++){
obj.add();
}
}
}).start();
//线程2
new Thread(new Runnable(){
public void run() {
for(int i = 0;i < 5;i++){
obj.del();
}
}
}).start();
//主线程
while(Thread.activeCount() > 1){
Thread.yield();
}
System.out.println("main:"+obj.count);
}
}
我们来分析一下上面的代码,线程1 和线程2 都是对obj 这个对象进行操作,当线程1 执行add()方法的时候拿到了obj 这个对象作为锁,此时线程2 不能进行del()方法。当线程1 执行完了add()方法之后线程2 才能运行,这样就实现了线程间的通信。
这种方法本质上是共享变量式通信,谁拿到了锁谁就可以执行。
while 轮询方式
这种方式是两个线程一个线程不断地改变条件,另一个线程里有一个while 循环,不断判断条件,直到条件成立,开始执行执行其他的代码块,其实这就是多个线程同时执行,这中方式会牺牲部分CPU性能。
class Obj{
int count = 0;
public synchronized void add(){
//do something
count++;
}
public synchronized void del(){
//do something
count--;
}
}
public class Demo4 {
static Obj obj = new Obj();
public static void main(String[] args) {
//线程1
new Thread(new Runnable(){
@Override
public void run() {
for(int i = 0;i < 10;i++){
obj.add();
System.out.println("++");
}
}
}).start();
//线程2
new Thread(new Runnable(){
@Override
public void run() {
boolean b = true;
while(b){
if(obj.count == 5){
System.out.println("线程2 退出了");
b = false;
}
}
}
}).start();;
}
上面的代码中,当线程2 的条件不满足时,它一直在进行无意义的循环。
wait() / notify() 方式
这种方式有一个经典的例子就是生产者—消费者模型,当仓库货物不足时,消费者就要等待,生产者生产足够的货物是给消费者发送一个消息,消费者才可以继续运行。同样,当仓库满了之后生产者就需要停止一段时间,等到一部分货物消费出去之后消费者发送消息给生产者,表示生产者可以继续工作了。
class Model {
private int count;
public Model(){
this.count = 1000;
}
public synchronized void produce(int val){
if(count > 5000){
try {
System.out.println("仓库已满");
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
count += val;
System.out.println("生产 1000-当前容量:"+get());
this.notify();
}
}
public synchronized void consume(int val){
if(count < val){
System.out.println("容量不足-当前容量:"+get());
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
count -= val;
System.out.println("消费 2000-仓库容量:"+get());
this.notifyAll();
}
}
public int get(){
return this.count;
}
}
public class Demo8 {
public static void main(String[] args) {
final Model model = new Model();
/**
* 生产者
*/
new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
model.produce(1000);
}
}
}).start();
/**
* 消费者
*/
new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
model.consume(2000);
}
}
}).start();
}
}
运行结果:
容量不足-当前容量:1000
生产 1000-当前容量:2000
消费 2000-仓库容量:0
生产 1000-当前容量:1000
容量不足-当前容量:1000
生产 1000-当前容量:2000
生产 1000-当前容量:3000
消费 2000-仓库容量:1000
生产 1000-当前容量:2000
消费 2000-仓库容量:0
生产 1000-当前容量:1000
容量不足-当前容量:1000
生产 1000-当前容量:2000
消费 2000-仓库容量:0