您的位置:首页 > 编程语言 > Java开发

Java多线程与并发应用-(4)-传统线程通信技术试题

2015-04-14 21:28 603 查看
package com.lipeng;

public class LoopDemo {

/**
* 线程A循环10次,然后线程B循环100次,然后A再循环10次,然后B再循环100次。如此循环50次。
* lipeng
* 2015-4-10
* @param args
*/
public static void main(String[] args) {
MyTask task=new MyTask();
RunA runA=new RunA(task);
RunB runB=new RunB(task);
new Thread(runA,"A").start();  //每个线程的start方法只能运行一次,但Run方法在不同的线程中可以运行多次。
new Thread(runB,"B").start();
}
}

class RunA implements Runnable
{
private MyTask task;
public RunA(MyTask task)
{
this.task=task;
}
@Override
public void run() {
try {
for(int i=0;i<50;i++)
{
task.A();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


class RunB implements Runnable
{
private MyTask task;
public  RunB(MyTask task)
{
this.task=task;
}
@Override
public void run() {
try {
for(int i=0;i<50;i++)
{
task.B();
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


class MyTask
{
private boolean aGo=true;//切换开关,当true时A执行,false时B执行,执行完后切换条件
public synchronized void A()throws Exception{
while(!aGo)  //为何不用if???
{
//A 不能运行,等待
this.wait();
}
for(int i=0;i<10;i++)
{
System.out.println("AAAAA--------------"+i);
}
//运行完之后,将aGo切换为FALSE,让B运行
aGo=false;
this.notify();//唤醒一个正在等待的线程
}

public synchronized void B()throws Exception{
while(aGo)
{
//B 不能运行,等待
this.wait();
}
for(int i=0;i<100;i++)
{
System.out.println("B--------------"+i);
}
//运行完之后,将aGo切换为true,让A运行
aGo=true;
this.notify();//唤醒一个正在等待的线程
}
}


说明:
1. 如果有大于两个多线程在执行,最好用notifyAll,为什么?

例如,如果本例中多起几个线程,如果此时有A1,B1线程在wait,某个A线程执行完,将aGo置为false,并唤醒正在等待锁的其中一个线程,A1或B1,如果此时正好A1线程抢到了CPU,则A1运行,判断方法A1进入wait状态,而B1由于没有被唤醒,之后继续等待,那么到最后,A1和B1都处于wait状态,造成了死锁。

而如果改为notifyAll的话,A1和B1都被唤醒,抢到锁的线程先执行,如果A1抢到的话,继续等待,然后B1继续执行,因为此时aGo=false,所以B1执行,将aGo=true,A1继续执行完毕。

结论:只要A和B启动的线程的个数不同,就可能造成死锁的情况。

2.
判断aGo的地方为什么要使用while,if不行吗?在wait方法说明中,也推荐使用while,因为在某些特定的情况下,线程有可能被假唤醒,使用while会循环检测更稳妥。在本例中,A和B应该是交替运行的,但是如果多启动几个线程,如果有A1线程在等待(wait)状态,而A2线程执行完毕,aGo设置为false,唤醒正在等待的线程(可能是A也可能是B),如果是A被唤醒的话,如果用了if而不是while,那么A执行,这样A就连续执行了两遍,不符合我们的设计要求,但如果换用while的话,即使A被唤醒,他会再次判断aGo的值,发现是false,则继续等待。直到B线程将其唤醒。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐