java - 使用 wait() 和 Notify() 在 4 个线程之间执行线程间通信时出现 IllegalMonitorStateException

标签 java multithreading

我只想在下一回合等于当前线程时运行线程,例如如果 nextTurn = 3,则只有为玩家 3 创建的线程应该运行,其他线程应该等待状态。对于其他线程也是如此,下面的程序不断地无限次地改变转弯,所以我希望特定于转弯的线程应该运行无限时间。

 import static java.util.Collections.shuffle;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

public class DemoMain {

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        int sizeOfDeck = 31;
        System.out.println("Enter cards in the Deck");
        ArrayList<Integer> cardNumber = new ArrayList<Integer>(sizeOfDeck);
//      for (int i = 0; i <= sizeOfDeck; i++) {
//          Scanner input = new Scanner(System.in);
//          cardNumber.add(input.nextInt());
//      }
        for(int i=0 ; i<=31;i++)
        {
            cardNumber.add(i);
        }
        System.out.println("Cards: "+ cardNumber );

        shuffle(cardNumber);
        List<Integer> Piles1 = cardNumber.subList(0, 4);
        List<Integer> Piles2 = cardNumber.subList(4, 8);
        List<Integer> Piles3 = cardNumber.subList(8, 12);
        List<Integer> Piles4 = cardNumber.subList(12, 16);

        List<Integer> player1Card = cardNumber.subList(16, 20);
        List<Integer> player2Card = cardNumber.subList(20, 24);
        List<Integer> player3Card = cardNumber.subList(24, 28);
        List<Integer> player4Card = cardNumber.subList(28, 32);

        Map<Integer, Integer> player1Map = getPlayerCards(player1Card);
        Map<Integer, Integer> player2Map = getPlayerCards(player2Card);
        Map<Integer, Integer> player3Map = getPlayerCards(player3Card);
        Map<Integer, Integer> player4Map = getPlayerCards(player4Card);


        Player p1 = new Player(player1Map, Piles1, Piles2, "Player1");
        Player p2 = new Player(player2Map, Piles2, Piles3, "Player2");
        Player p3 = new Player(player3Map, Piles3, Piles4, "Player3");
        Player p4 = new Player(player4Map, Piles4, Piles1, "Player4");


        p1.start();

        p2.start();

        p3.start();

        p4.start();


    }

    private static Map<Integer, Integer> getPlayerCards(List<Integer> playerCard) {

        Map<Integer, Integer> cardsMap = null;

        for (Integer card : playerCard) {
            if (cardsMap == null) {
                cardsMap = new HashMap<Integer, Integer>();
            }

            Integer count = cardsMap.get(card);
            if (count == null) {
                cardsMap.put(card, 1);
            } else {
                cardsMap.put(card, cardsMap.get(card) + 1);
            }
        }

        return cardsMap;
     }
    }

Player.java

import java.util.List;
import java.util.Map;

public class Player extends Thread {

    private Map<Integer, Integer> holdings;
    private List<Integer> deckToUseToDraw;
    private List<Integer> deckToUseForDiscard;
    private Integer currentlyDrawnCard;
    private String playerTrun;
    private boolean hasWon = false;
    //static String Nextturn = "Player1";
    StringBuffer Nextturn =  new StringBuffer("Player1");




    public Player(Map<Integer, Integer>holdings, List<Integer> drawDeck, List<Integer> discardDeck, String playerTurn) {
        this.holdings = holdings;
        this.deckToUseToDraw = drawDeck;
        this.deckToUseForDiscard = discardDeck;
        this.playerTrun = playerTurn;
    }







    public void run() {
        try {
            playNew();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    private void playNew() throws InterruptedException {
        synchronized (Nextturn) {
            while(true) {               
                if (! playerTrun.equalsIgnoreCase(String.valueOf(Nextturn))) {
                    try {
                        System.out.println("waiting: "+ playerTrun);
                        Nextturn.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    System.out.println("Running: "+playerTrun);
                    nextTurn();
                    Nextturn.notifyAll();

                }
            }
        }
    }

    public void nextTurn()
    {


        if(playerTrun.equalsIgnoreCase("Player1"))
                Nextturn =  new StringBuffer("Player2");
        else if(playerTrun.equalsIgnoreCase("Player2"))
                Nextturn = new StringBuffer("Player3");
        else if(playerTrun.equalsIgnoreCase("Player3"))
                Nextturn =  new StringBuffer("Player4");
        else if(playerTrun.equalsIgnoreCase("Player4"))
                Nextturn = new StringBuffer("Player1");



    }
}

最佳答案

要在对象上使用wait()/notify(),线程必须拥有该对象上的监视器。
由于您创建了一个新的 StringBuffer 实例并将其分配给 Nextturn,同时线程拥有监视器:

Nextturn = new StringBuffer("Player1");

我认为当前线程丢失了监视器,或者至少在新对象上没有监视器。因此,您无法再在 Nextturn 上调用 wait()/notify()
例如这里:

nextTurn(); // you assign the variable to a new object
Nextturn.notifyAll(); // but you notify on that new object

作为替代方案,使用一个简单的对象来表示回合的锁定,并使用一个 String 来表示当前玩家:

final Object lockOnTurn = new Object();
String currentPlayer = "...";
// ..
private void playNew() throws InterruptedException {
    synchronized (lockOnTurn) {
        while(true) {               
            if (! playerTrun.equalsIgnoreCase(String.valueOf(currentPlayer))) {
                try {
                    System.out.println("waiting: "+ playerTrun);
                    lockOnTurn.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                System.out.println("Running: "+playerTrun);
                currentPlayer = nextTurn();
                lockOnTurn.notifyAll();
            }
        }
    }
}

关于java - 使用 wait() 和 Notify() 在 4 个线程之间执行线程间通信时出现 IllegalMonitorStateException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57979454/

相关文章:

java - java中的多线程持久队列

java - 创建一个以有限速率发出项目的 Flowable,以避免需要缓冲事件

java - 了解 ForkJoinTask 的 invokeAll 方法

使用 ContentProvider 进行 Android 单元测试

java - 如何打印 List<Object[]> 值?

java - 如果java是按值传递的,为什么我的对象在执行方法后会发生变化?

java - MVP 模式中的 Mockito 测试

java - 如何使用 Java 从 Windows (MSCAPI) 上的智能卡获取用户身份?

python - 在 PyQt 中启动 new QThread() 时传递参数

java - 如何将InputStream转换为字符串?