=explaination>本节将讨论如何控制互相交互线程的间运行进度,即多线程的间同步问题,下面我们将通过多线程同步模型: 生产者-消费者问题来介绍说明怎样实现多线程同步
=pt9-black> 我们把系统中使用某类资源线程称为消费者产生或释放同类资源线程称为生产者
在下面Java应用中生产者线程向文件中写数据消费者从文件中读数据这样在这个中同时运行两个线程共享同个文件资源通过这个例子我们来了解怎样使它们同步
JAVA/text/ch06/se02/right6_2_2.htm#\">--观看动画--
\" width=38 align=absBottom> 例6.5
SyncStack{ //同步堆栈类
private index = 0; //堆栈指针值为0
private char buffer = char[6]; //堆栈有6个空间
public synchronized void push(char c){ //加上互斥锁
while(index = = buffer.length){ //堆栈已满不能压栈
try{
this.wait; //等待直到有数据出栈
}catch(InterruptedException e){}
}
=pt9-black> this.noty; //通知其它线程把数据出栈
buffer[index] = c; //数据入栈
index; //指针向上移动
}
public synchronized char pop{ //加上互斥锁
while(index 0){ //堆栈无数据不能出栈
try{
this.wait; //等待其它线程把数据入栈
}catch(InterruptedException e){}
}
this.noty; //通知其它线程入栈
index- -; //指针向下移动
buffer[index]; //数据出栈
}
}
Producer implements Runnable{ //生产者类
SyncStack theStack;
//生产者类生成字母都保存到同步堆栈中
public Producer(SyncStack s){
theStack = s;
}
public void run{
char c;
for( i=0; i<20; i){
c =(char)(Math.random*26+\'A\');
//随机产生20个
theStack.push(c); //把入栈
.out.prln(\"Produced: \"+c); //打印
try{
Thread.sleep(()(Math.random*1000));
/*每产生个线程就睡眠*/
}catch(InterruptedException e){}
}
}
}
Consumer implements Runnable{ //消费者类
SyncStack theStack;
//消费者类获得都来自同步堆栈
public Consumer(SyncStack s){
theStack = s;
}
public void run{
char c;
for( i=0;i<20;i){
c = theStack.pop; //从堆栈中读取
.out.prln(\"Consumed: \"+c);
//打印
try{
Thread.sleep(()(Math.random*1000));
/*每读取个线程就睡眠*/
}catch(InterruptedException e){}
}
}
}
public SyncTest{
public void (String args){
SyncStack stack = SyncStack;
//下面消费者类对象和生产者类对象所操作是同个同步堆栈对象
Runnable source= Producer(stack);
Runnable sink = Consumer(stack);
Thread t1 = Thread(source); //线程例子化
Thread t2 = Thread(sink); //线程例子化
t1.start; //线程启动
t2.start; //线程启动
}
}
类Producer是生产者模型其中 run思路方法中定义了生产者线程所做操作循环push思路方法,将生产20个字母送入堆栈中每次执行完push操作后sleep思路方法睡眠段随机时间以给其他线程执行机会类Consumer是消费者模型循环pop思路方法,从堆栈中取出个数据共取20次每次执行完pop操作后sleep思路方法睡眠段随机时间以给其他线程执行机会
执行结果
Produced:V
Consumed:V
Produced:E
Consumed:E
Produced:P
Produced:L
...
Consumed:L
Consumed:P
在上述例子中通过运用wait和noty思路方法来实现线程同步在同步中还会用到notyAll思路方法般来说每个共享对象互斥锁存在两个队列个是锁等待队列另个是锁申请队列锁申请队列中第个线程可以对该共享对象进行操作而锁等待队列中线程在某些情况下将移入到锁申请队列下面比较下wait、noty和notyAll思路方法:
(1) wait,nofity,notyAll必须在已经持有锁情况下执行,所以它们只能出现在synchronized作用范围内也就是出现在用 synchronized修饰思路方法或类中
(2) wait作用:释放已持有锁,进入等待队列.
(3) noty作用:唤醒wait队列中第个线程并把它移入锁申请队列.
(4) notyAll作用:唤醒wait队列中所有线程并把它们移入锁申请队列.
注意:
1) suspend和resume
在JDK1.2中不再使用suspend和resume,其相应功能由wait和noty来实现
2) stop
在JDK1.2中不再使用stop,而是通过标志位来使正常执行完毕例6.6就是个典型例子
=pt9-black>\" width=38 align=absBottom> 例6.6
public Xyz implements Runnable {
private boolean timeToQuit=false; //标志位值为假
public void run {
while(!timeToQuit) {//只要标志位为假线程继续运行
…
}
}
=pt9-black> public void stopRunning {
timeToQuit=true;} //标志位设为真表示正常结束
}
public ControlThread {
private Runnable r= Xyz;
private Thread t= Thread(r);
public void startThread {
t.start;
}
public void stopThread {
r.stopRunning; }
//通过stopRunning思路方法来终止线程运行
}
最新评论