`

对java 多线程 wait notify notifyAll 的理解

    博客分类:
  • java
阅读更多
3个人玩游戏一台手柄游戏,一次只能有一个人玩  示例代码1

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();
    }
}

执行结果:
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个线程再次竞争,直至都执行完毕。

总结:
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 ,就会报这个错误。

用三个线程打印出连续10次的ABC,要求1个线程打A,1个线程打B,1个线程打C, 示例代码:
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(); 
    } 
}
执行结果:
ABCABCABCABCABCABCABCABCABCABC

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


分享到:
评论

相关推荐

    源码—Java多线程5—死锁和wait notify notifyAll

    源码—Java多线程5—死锁和wait notify notifyAll

    Java 同步方式 wait和notify/notifyall

    总结一下,`wait()`, `notify()`, 和 `notifyAll()` 是Java多线程编程中的核心工具,它们与`synchronized`关键字一起,为线程间的协作提供了强大的支持。理解并熟练掌握这些概念,对于编写高效、安全的多线程程序至...

    Java多线程wait和notify

    总结来说,Java的 `wait()` 和 `notify()` 提供了一种在多线程环境中控制线程执行的机制。通过合理使用这些方法,我们可以实现线程间的协作,精确控制子线程的运行状态。然而,这种方式虽然灵活,但管理起来相对复杂...

    浅谈java多线程wait,notify

    在本文中,我们将通过示例代码详细介绍Java多线程wait和notify的使用,帮助读者更好地理解和掌握这两个机制。 wait机制 在Java中,wait机制用于暂停当前线程的执行,并释放当前对象的锁,以便让其他线程获得锁并...

    Java多线程中wait、notify、notifyAll使用详解

    Java多线程中wait、notify、notifyAll使用详解 Java中多线程编程中,wait、notify、notifyAll三个方法是非常重要的,它们都是Object对象的方法,用于线程之间的通信。下面我们将详细介绍这三个方法的使用和作用。 ...

    java之wait,notify的用法([ 详解+实例 ])

    在Java多线程编程中,wait和notify是两个非常重要的方法,它们都是Object类的方法,用于线程之间的通信和同步。下面我们将详细解释wait和notify的用法。 wait方法 wait方法是Object类的一个方法,用于让当前线程...

    基于Java多线程notify与notifyall的区别分析

    Java中的多线程编程是构建高效并发应用的关键技术之一,其中`wait()`、`notify()`和`notifyAll()`是Java对象锁机制中的三个关键方法,它们位于`java.lang.Object`类中,主要用于线程间通信。本文将深入探讨`notify()...

    Java多线程同步(wait()notify()notifyAll())[文].pdf

    总之,Java多线程同步通过wait()、notify()和notifyAll()等方法,配合synchronized关键字,实现了对共享资源的访问控制,保证了程序的正确性。同时,原子操作和volatile关键字提供了更细粒度的线程安全保证。理解并...

    如何在Java中正确使用 wait, notify 和 notifyAll

    wait, notify 和 notifyAll,这些在多线程中被经常用到的保留关键字,在实际开发的时候很多时候却并没有被大家重视。本文对这些关键字的使用进行了描述。  在 Java 中可以用 wait、notify 和 notifyAll 来实现...

    Java多线程知识点总结

    同样,当线程使用wait方法时,它会主动释放锁并进入等待状态,直到其他线程调用notify或notifyAll方法来唤醒它。此外,sleep方法可以使线程进入阻塞状态一段时间,而join方法则允许一个线程等待另一个线程完成其任务...

    Java 同步锁 wait notify 学习心得

    标题和描述概述的知识点主要集中在Java的多线程机制中,特别是`wait`和`notify`方法在同步锁中的应用。这些方法对于控制线程之间的交互至关重要,尤其是在资源有限或需要确保数据一致性的情况下。 ### Java同步锁...

    汪文君JAVA多线程编程实战(完整不加密)

    学习《汪文君JAVA多线程编程实战》不仅能够提高读者对Java多线程编程的理解,还有助于培养良好的并发编程习惯,避免常见的并发陷阱。对于想要提升自己在并发编程领域技能的Java开发者来说,这本书无疑是一份宝贵的...

    java多线程的讲解和实战

    Java多线程是Java编程中的重要概念,尤其在如今的多核处理器环境下,理解并熟练掌握多线程技术对于提高程序性能和响应速度至关重要...通过对这些知识点的学习和实践,读者可以深入理解Java多线程的运用,提升编程技能。

    JAVAJAVA多线程教学演示系统论文

    3. **线程同步与并发控制**:论文会深入讲解JAVA中的线程同步机制,如synchronized关键字、wait()、notify()和notifyAll()方法,以及Lock接口和ReentrantLock类的使用。此外,可能会探讨并发工具类,如Semaphore、...

    java 多线程并发实例

    在Java编程中,多线程并发是...总之,Java的多线程并发实例可以帮助我们更好地理解和实践线程控制、同步机制以及经典的设计模式,提升我们的编程能力。通过不断学习和实践,我们可以编写出高效、安全的多线程并发程序。

    java多线程经典案例

    Java中,可以通过wait()、notify()和notifyAll()这三个Object类的方法来实现线程间的通信。这些方法必须在同步环境中使用,否则会抛出异常。此外,Java 5引入了BlockingQueue阻塞队列,它是一种线程安全的数据结构,...

    Java多线程机制(讲述java里面与多线程有关的函数)

    Java多线程机制是Java编程中至关重要的一部分,它允许程序同时执行多个任务,提升应用程序的效率和响应性。以下是对各个知识点的详细说明: 9.1 Java中的线程: Java程序中的线程是在操作系统级别的线程基础上进行...

    java多线程设计模式详解(PDF及源码)

    wait set——线程的休息室 wait方法——把线程放入wait set notify方法——从wait set拿出线程 notifyAll方法——从wait set拿出所有线程 wait、notify、notifyAll是Object类的方法 线程的状态移转 跟线程有关的其他...

    java多线程进度条

    为了在多线程中同步进度更新,我们可以利用synchronized关键字、wait()、notify()方法,或者使用Java并发库中的高级工具,如Semaphore、CyclicBarrier或CountDownLatch等。 一个简单的进度条实现可以采用共享变量...

    JAVA多线程编程技术PDF

    Java提供了wait(), notify()和notifyAll()方法,这些方法用于在线程间交换信息,但必须在同步块中使用,以防止死锁和其他并发问题。此外,还有java.util.concurrent工具包,包含如BlockingQueue等高级并发结构,它们...

Global site tag (gtag.js) - Google Analytics