【问题标题】:JFrame freezes when I try to interrupt threads当我尝试中断线程时,JFrame 冻结
【发布时间】:2015-11-14 11:30:04
【问题描述】:

我在这个练习中遇到了这个问题,我有 3 个类,一个 Provider(Thread),它不断提供存储在 LinkedList 中的整数产品。一旦它至少达到 10 号,Retailers(Thread) 就可以全部购买。还有协调线程的分发器。 产品显示在 JFrame 上,然后当我单击停止按钮时,每个线程都会停止,每个零售商都会告诉他们购买了多少产品。

编辑:忘记提出问题,每次单击停止按钮时,应用程序都会冻结,我什至无法关闭 JFrame 窗口,不明白为什么。

 public class Distributor {

    private JTextField textfield = new JTextField();
    private LinkedList<Integer> productList = new LinkedList<Integer>();
    private JFrame frame = new JFrame("Window");
    private JButton btn = new JButton("Stop");
    private Thread provider = new Thread(new Provider(this));
    private LinkedList<Thread> retailerList = new LinkedList<Thread>();

    private void addRetailer(int num) {
        for (int i = 0; i < num; i++)
            retailerList.add(new Thread(new Retailer(i, this)));
    }

    public Distributor() {
        frame.setSize(300, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.add(textfield);
        frame.add(btn, BorderLayout.SOUTH);
        addRetailer(2);


        btn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    provider.interrupt();
                    provider.join();
                    System.out.println(provider.isAlive());

                    for (Thread t : retailerList) {
                        t.interrupt();
                        t.join();
                        System.out.println(t.isAlive());
                    }
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
        });
    }

    public void execute() {
        frame.setVisible(true);
        provider.start();
        for (Thread t : retailerList)
            t.start();
    }

    // Keeps providing products, and notifies retailers when there are 10 products
    public synchronized void provide(int product) {
        textfield.setText(productList.toString());
        productList.add(product);
        if (productList.size() == 10)
            notifyAll();
    }

    // Sells all the products if there are at least 10 to sell.
    public synchronized int sell() throws InterruptedException {
        while (productList.size() < 10)
            wait();

        int total = productList.size();
        notifyAll();
        textfield.setText(productList.toString());
        productList.clear();
        return total;
    }
}

提供者类:

public class Provider implements Runnable {
private Distributor distribuidor;
private int total = 0;

public Provider(Distributor distribuidor) {
    super();
    this.distribuidor = distribuidor;
}

@Override
public void run() {
    while (!Thread.interrupted()) {
        try {
            distribuidor.provide((int) (Math.random() * 10) + 1);
            Thread.sleep(10);
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
    System.out.println("Provider Interrupted");
 }
}

零售商类:

public class Retailer implements Runnable {

private Distributor distributor;
private int total = 0;
private int id;

public Retailer(int id, Distributor distributor) {
    super();
    this.id = id;
    this.distributor = distributor;
}

@Override
public void run() {
    while (!Thread.interrupted()) {
        try {
            total += distributor.sell();
            Thread.sleep(10);
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
    System.out.println("Retailer id: " + id + " bought: " + total + " products");
 }
}

还有主类:

public class Main {
    public static void main(String[] args) {
        Distributor distributor = new Distributor();
        distributor.execute();
    }
}

【问题讨论】:

  • Ops 对不起我的错,问题是每次我点击停止按钮时,它应该会中断线程,但是 Frame 冻结并且没有任何反应。应用程序甚至无法关闭,必须通过任务管理器来完成。
  • 您正在阻止 EDT。另请参阅java.util.concurrent,对于example

标签: java multithreading swing jframe


【解决方案1】:

不要在循环内捕获 InterruptedException,而是将循环放在 try { ... }

提供者类:

public class Provider implements Runnable {

    private Distributor distribuidor;
    private int total = 0;

    public Provider(Distributor distribuidor) {
        super();
        this.distribuidor = distribuidor;
    }

    @Override
    public void run() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                distribuidor.provide((int) (Math.random() * 10) + 1);
                Thread.sleep(10);
            }
        } catch (InterruptedException interruptedException) {
        }
        System.out.println("Provider Interrupted");
    }
}

零售商类:

public class Retailer implements Runnable {

    private Distributor distributor;
    private int total = 0;
    private int id;

    public Retailer(int id, Distributor distributor) {
        super();
        this.id = id;
        this.distributor = distributor;
    }

    @Override
    public void run() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                total += distributor.sell();
                Thread.sleep(10);
            }
        } catch (InterruptedException interruptedException) {
        }
        System.out.println("Retailer id: " + id + " bought: " + total + " products");
    }
}

【讨论】:

    【解决方案2】:

    问题是您的Thread 实际上永远不会停止,并且 EDT 也被阻止了。

    我建议您使用布尔值来停止 Provider 内的无限循环。


    提供者

    class Provider implements Runnable {
        private Distributor distribuidor;
        private int total = 0;
        private boolean isRunning = true;
    
        public void setIsRunning(boolean bool){
            isRunning = bool;
        }
    
        public Provider(Distributor distribuidor) {
            super();
            this.distribuidor = distribuidor;
        }
    
        @Override
        public void run() {
            while (isRunning) {
                try {
                    distribuidor.provide((int) (Math.random() * 10) + 1);
                    Thread.sleep(1000);
                } catch (Exception e) {
                    // TODO: handle exception
                }
            }
            System.out.println("Provider Interrupted");
        }
    }
    

    在您的 Distributor 课程中,更改以下内容:

    private Provider pro = new Provider(this);
    private Thread provider = new Thread(pro);
    

    btn.addActionListener(new ActionListener() {
    
        @Override
        public void actionPerformed(ActionEvent e) {
            try {
                pro.setIsRunning(false);
                provider.interrupt();
                provider.join();
                System.out.println(provider.isAlive());
    
                for (Thread t : retailerList) {
                    t.interrupt();
                    t.join();
                    System.out.println(t.isAlive());
                }
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
    });
    

    点击停止按钮后的输出

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-10
      • 1970-01-01
      • 1970-01-01
      • 2015-02-16
      • 1970-01-01
      • 2011-03-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多