对java 多线程 wait notify notifyAll 的理解

[b]3个人玩游戏一台手柄游戏,一次只能有一个人玩 示例代码1[/b]

public class Player implements Runnable {
private final int id;
private Game game;

public Player(int id, Game game) {
this.id = id;
this.game = game;
}


public String toString() {
return "Athlete<" + id + ">";
}

public int hashCode() {
return new Integer(id).hashCode();
}

public void playGame() throws InterruptedException{
System.out.println(this.toString() + " ready!");
game.play(this);
}

public void run() {
try {
playGame();
} catch (InterruptedException e) {
System.out.println(this + " quit the game");
}
}
}

public class Game implements Runnable {
private boolean start = false;

public void play(Player player) throws InterruptedException {
synchronized (this) {
System.out.println(player.toString()+"获得锁");
while (!start){
System.out.println(player.toString()+"在等待");
wait();
System.out.println( player.toString()+"被唤醒了");
}

if (start)
System.out.println(player + " have played!");
}
}

//通知所有玩家
public synchronized void beginStart() {
start = true;
notifyAll();
}

public void run() {
start = false;
System.out.println("Ready......");
System.out.println("Ready......");
System.out.println("game start");
beginStart();//通知所有玩家游戏准备好了
}

public static void main(String[] args) throws InterruptedException {
Set<Player> players = new HashSet<Player>();
//实例化一个游戏
Game game = new Game();

//实例化3个玩家
for (int i = 0; i < 3; i++)
players.add(new Player(i, game));

//启动3个玩家
Iterator<Player> iter = players.iterator();
while (iter.hasNext())
new Thread(iter.next()).start();
Thread.sleep(100);

//游戏启动
new Thread(game).start();
}
}

[b]执行结果:[/b]
Athlete<0> ready!
Athlete<1> ready!
Athlete<2> ready!
Athlete<0>获得锁
Athlete<0>在等待
Athlete<2>获得锁
Athlete<2>在等待
Athlete<1>获得锁
Athlete<1>在等待
Ready......
Ready......
game start
Athlete<1>被唤醒了
Athlete<1> have played!
Athlete<2>被唤醒了
Athlete<2> have played!
Athlete<0>被唤醒了
Athlete<0> have played!

游戏对象game只有1个,synchronized (this)锁的实际就是game对象, 三个玩家线程都依次得到锁并在wait等待时释放锁。启动游戏线程时,通知所有线程,三个玩家线程需要竞争同步锁,得到同步锁的线程执行完synchronized(this)代码块后,自动释放同步锁,处于同步锁阻塞的剩下的2个线程再次竞争,直至都执行完毕。

[b]总结:[/b]
wait()会释放锁,下一次被唤醒并获得锁时,会紧接着wait的下一行开始执行。
obj.notifyAll()是唤醒所有在obj上等待的线程,但是notifyAll 不会释放锁,执行完synchronized 代码块时,才会释放锁。(注意:obj.notifyAll()只是唤醒所有在obj上等待的线程,并不会唤醒应用中无关的线程)
notify()是通知一个线程,notifyAll()时通知所有线程,如果上面的例子beginStart方法的notifyAll()改为notify,那么就只有一个人能玩游戏,wait状态的线程如果没被唤醒,会一直的等待,即使锁没被占用。
wait() notify() notifyAll()方法必须写在同步方法或者同步块之内,并且同步的锁必须与调用等待方法和通知方法是同一个对象(比如:synchronized(obj1){},那么调用等待方法的也必须是obj1),否则会报java.lang.IllegalMonitorStateException异常,就是因为没有拥有锁导致的。例如上例的beginStart方法,去掉synchronized ,就会报这个错误。

[b]用三个线程打印出连续10次的ABC,要求1个线程打A,1个线程打B,1个线程打C, 示例代码:[/b]
public class PrintABC {

public static Boolean isThreadA = true;
public static Boolean isThreadB = false;
public static Boolean isThreadC = false;

public static void main(String[] args) {
final PrintABC abc = new PrintABC();
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (abc) {
while(!isThreadA) {
try {
abc.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.print("A");
isThreadA = false;
isThreadB = true;
isThreadC = false;
abc.notifyAll();
}
}
}
}).start();

new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (abc) {
while(!isThreadB) {
try {
abc.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.print("B");
isThreadA = false;
isThreadB = false;
isThreadC = true;
abc.notifyAll();
}
}
}
}).start();

new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (abc) {
while(!isThreadC) {
try {
abc.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.print("C");
isThreadA = true;
isThreadB = false;
isThreadC = false;
abc.notifyAll();
}
}
}
}).start();
}
}
[b]执行结果:[/b]
ABCABCABCABCABCABCABCABCABCABC

abc对象是三个线程共同的锁,存在竞争。for循环中刚好可以使每个字母打印10次,for循环每次都需要竞争abc锁,竞争得到abc锁时,条件不符合则等待并释放锁,让其他线程竞争,条件符合则打印字母,打印完成后,会通知所有的线程,在执行完synchronized 块时,会释放锁。
注意:notifyAll 和wait方法的调用对象是锁,所以写成abc.notifyAll();abc.wait(); 3人玩游戏的那个例子,之所以能不写调用的对象,是因为锁就是this ,不写也是等价。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值