Java多线程暂停

Java多线程暂停,java,multithreading,Java,Multithreading,我的目标 我是java多线程的新手,我正在尝试创建pong。我将只在这里包含一点与问题相关的代码 问题 我想通过按空格键暂停游戏,然后再按空格键继续游戏。以下代码用于暂停游戏,但无法继续。未来所有按键都无法识别。似乎主线程正在暂停 代码 主类 public class MainManager { private Ticker ticker; private Thread tickerThread; private boolean active; public

我的目标

我是java多线程的新手,我正在尝试创建pong。我将只在这里包含一点与问题相关的代码

问题

我想通过按空格键暂停游戏,然后再按空格键继续游戏。以下代码用于暂停游戏,但无法继续。未来所有按键都无法识别。似乎主线程正在暂停

代码

主类

public class MainManager {

    private Ticker ticker;
    private Thread tickerThread;

    private boolean active;

    public MainManager() {
        ticker = new Ticker(this,10);
        tickerThread = new Thread(ticker);

        tickerThread.start();
    }

    public synchronized void tick() {
        // Does necesary things for each game tick
    }

    public void toggleState() {
        if (this.active) {
            ticker.pause();
        } else {
            this.setActive(true);
            notify();
        }
    }

    public void setActive(boolean b) {
        this.active = b;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
                    @Override
                   public void run() {
                        MainManager manager = new MainManager();
                   }
        });
    }
}
public class Ticker implements Runnable {

    private MainManager manager;
    private int tick;

    public Ticker(MainManager manager,int tick) {
        this.manager = manager;
        this.tick = tick;
    }

    @Override
    public void run() {
        manager.setActive(true);
        while (true) {
            try {
                Thread.sleep(this.tick);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            manager.tick();
        }
    }

    public void setTickSpeed(int speed) {
        this.tick = speed;
    }   

    public synchronized void pause() {
        synchronized(manager) {
            try {
                System.out.println("Waiting for Manager");
                manager.setActive(false);
                manager.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
股票类

public class MainManager {

    private Ticker ticker;
    private Thread tickerThread;

    private boolean active;

    public MainManager() {
        ticker = new Ticker(this,10);
        tickerThread = new Thread(ticker);

        tickerThread.start();
    }

    public synchronized void tick() {
        // Does necesary things for each game tick
    }

    public void toggleState() {
        if (this.active) {
            ticker.pause();
        } else {
            this.setActive(true);
            notify();
        }
    }

    public void setActive(boolean b) {
        this.active = b;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
                    @Override
                   public void run() {
                        MainManager manager = new MainManager();
                   }
        });
    }
}
public class Ticker implements Runnable {

    private MainManager manager;
    private int tick;

    public Ticker(MainManager manager,int tick) {
        this.manager = manager;
        this.tick = tick;
    }

    @Override
    public void run() {
        manager.setActive(true);
        while (true) {
            try {
                Thread.sleep(this.tick);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            manager.tick();
        }
    }

    public void setTickSpeed(int speed) {
        this.tick = speed;
    }   

    public synchronized void pause() {
        synchronized(manager) {
            try {
                System.out.println("Waiting for Manager");
                manager.setActive(false);
                manager.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
KeyListener类

public class MainManager {

    private Ticker ticker;
    private Thread tickerThread;

    private boolean active;

    public MainManager() {
        ticker = new Ticker(this,10);
        tickerThread = new Thread(ticker);

        tickerThread.start();
    }

    public synchronized void tick() {
        // Does necesary things for each game tick
    }

    public void toggleState() {
        if (this.active) {
            ticker.pause();
        } else {
            this.setActive(true);
            notify();
        }
    }

    public void setActive(boolean b) {
        this.active = b;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
                    @Override
                   public void run() {
                        MainManager manager = new MainManager();
                   }
        });
    }
}
public class Ticker implements Runnable {

    private MainManager manager;
    private int tick;

    public Ticker(MainManager manager,int tick) {
        this.manager = manager;
        this.tick = tick;
    }

    @Override
    public void run() {
        manager.setActive(true);
        while (true) {
            try {
                Thread.sleep(this.tick);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            manager.tick();
        }
    }

    public void setTickSpeed(int speed) {
        this.tick = speed;
    }   

    public synchronized void pause() {
        synchronized(manager) {
            try {
                System.out.println("Waiting for Manager");
                manager.setActive(false);
                manager.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
注意:该类被添加到在MainManager构造函数内部构造的JFrame中。如果这个JFrame类对我的问题很重要,我会发布代码,请告诉我


如何让
勾选器读取
暂停并按键继续?欢迎任何其他批评。

您从未离开Swing事件调度线程

您的股票代码在另一条线程中愉快地滴答作响,运行良好。但是,如果我们遵循您的切换调用的路径,它将永远不会到达另一个线程

按下空格键->Swing EDT witchcraft->按键->manager.toggleState()->ticker.pause()现在我们与manager同步,这并不难。我们还在主线上!然后我们等待

按下空格键->暂停Swing EDT。在另一个线程中运行的ticker的唯一部分是run方法


您希望在EDT之外运行与游戏逻辑相关的所有内容。在JFrame和事件处理程序的不同线程中运行MainManager和Ticker,并同步或使用锁定的布尔值将数据从IO线程发送到逻辑线程。

您的
notify()
应包含在同步块中。您的
active
布尔值应包含
volatile
关键字,对于原子性。在同步块中添加
notify()
不会产生任何影响。在
if(e.getKeyCode()==KeyEvent.VK_SPACE){
行上方的keyListener中,如果我放入
System.out.println(“Hello”);
它只在暂停前打印,即使我一直单击空格键,也不会在暂停后打印。调用wait()时,您正在挂起事件调度线程(Event dispatch thread)),因为它位于来自KeyListener(在EDT上调用)的调用链中。当然,这会终止任何进一步的事件分派;notify()只能来自KeyEvent,但这也是正在等待来自自身的通知的线程。决不能调用wait()在EDT上。@MouseEvent volatile对修改布尔值的原子性没有任何作用。它确实提供了可视性。@ryangoldtein我不确定我应该改变什么,当涉及到基本以外的任何东西时,我真的是java的超级高手。所以我对swing、线程、事件处理程序和同步知之甚少。