java 保护代码_java-并发-保护代码块

浏览以下内容前,请点击并阅读

线程经常需要协调其动作,最常用的协调方法就是保护代码块,该代码块以一个条件判断开始,当判断为true时才能开始执行。

假设一个方法guradedJoy必须等到变量joy由其他线程设定过后才能开始执行,这样的方法,理论上简单的循环直到满足条件就可以了,但是这样的循环是比较浪费资源的,因为等待的时候是在不停的执行的。

public voidguardedJoy() {//简单的循环保护,不建议这样做,因为比较浪费处理器时间

while(!joy) {}

System.out.println("Joy has been achieved!");

}

一个更高效的方法就是调用Object类的wait方法来暂停当前的线程,wait方法的调用只有在另外一个线程发出特定的事件已经发生的通知时才会返回,但该特定的事件不一定是这个线程正在等待的事件:

public synchronized voidguardedJoy() {//该保护用法只对于特定的事件循环一次,可以不是正在等待的事件

while(!joy) {try{

wait();

}catch(InterruptedException e) {}

}

System.out.println("Joy and efficiency have been achieved!");

}

注意:在一个测试一个等待条件的对于你所等待的条件的,或者等待的条件依然为true。

像其他暂停执行的方法一样,wait方法可以抛出InterruptException,当一个线程调用一个对象的wait方法时,该线程必须拥有该对象的内置锁(如上例中guardedJoy方法为同步方法),否则将抛出错误,在同步方法中调用wait方法是一个请求内置锁的简单途径。

当调用wait方法时,线程释放锁并暂停执行。在接下来的时间里,另外一个线程将请求同一个锁并调用对象的notifyAll,通知等待该锁的所有线程一些已经发生的重要事情。当第二个线程释放了锁之后,第一个线程就会请求该锁并从调用的wait方法中返回。

注意:还有另外一个通知的方法,notify,该方法只唤醒一个线程,因为notify方法无法指定要被唤醒的线程,这个方法只在大规模并行程序中有用,也就是说,程序中有许多线程做相同的事情,这样的程序中,不必在意唤醒的是哪个线程。

以下利用保护代码块来创建一个简单的生产者-消费者程序,给程序在两个线程之间分享数据,生产者产生数据,而消费者对数据进行处理,两个线程之间通过一个共享的对象进行通信。线程之间的协调是很重要的:消费者在生产者传递数据之间不能检索数据,而生产者在旧数据被消费者检索之前不能传递新的数据。

以下定义一个类用来创建通信的对象:

public classDrop {//生产者发给消费者的信息

privateString message;//如果消费者需要等待消费者发送信息则为true,如果需要等待消费者接受信息则为false

private boolean empty = true;public synchronizedString take() {//等待信息可用

while(empty) {try{

wait();

}catch(InterruptedException e) {}

}//转换状态

empty = true;//通知生产者信息已被检索

notifyAll();returnmessage;

}public synchronized voidput(String message) {//等待信息被检索

while (!empty) {try{

wait();

}catch(InterruptedException e) {}

}//转换状态

empty = false;//Store message.

this.message =message;//通知消费者状态已经改变

notifyAll();

}

}

定义一个Producer类,发送一系列熟悉的信息,字符串“DONE”表明所有的信息已经被发送,为模拟真实的程序,发送信息的间歇Producer类会停顿随机的一段时间。

//导入随机类,以产生一个随机数

importjava.util.Random;public class Producer implementsRunnable {privateDrop drop;publicProducer(Drop drop) {this.drop =drop;

}public voidrun() {

String importantInfo[]={"Mares eat oats","Does eat oats","Little lambs eat ivy","A kid will eat ivy too"};

Random random= newRandom();for (int i = 0;

i

i++) {

drop.put(importantInfo[i]);try{//停顿随机的一段时间

Thread.sleep(random.nextInt(5000));

}catch(InterruptedException e) {}

}

drop.put("DONE");

}

}

消费者线程定义由Consumer类定义,简单地检索并输出信息,直到其检索到“DONE”为止,该线程也会间歇也会停顿随机的时间:

importjava.util.Random;public class Consumer implementsRunnable {privateDrop drop;publicConsumer(Drop drop) {this.drop =drop;

}public voidrun() {

Random random= newRandom();for (String message =drop.take();! message.equals("DONE");

message=drop.take()) {

System.out.format("MESSAGE RECEIVED: %s%n", message);try{

Thread.sleep(random.nextInt(5000));

}catch(InterruptedException e) {}

}

}

}

最后在一个任意的类中定义一个主线程,ProducerConsumerExample,用以创建信息对象和启动生产者和消费者线程。

public classProducerConsumerExample {public static voidmain(String[] args) {

Drop drop= newDrop();

(new Thread(newProducer(drop))).start();

(new Thread(newConsumer(drop))).start();

}

}

以上的Drop类的创建是为了演示保护代码块的使用,java的集合框架(Java Collections Framework)提供了数据分享的类,提供丰富的功能,因此可以不必定义自己的类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值