Java线程挂

时间:2015-07-20 18:04:50

标签: java multithreading loops numbers flags

我正在编写具有2个线程的简单多线程代码。一个打印0到500之间的偶数,另一个打印1到500之间的奇数。我希望通过改变线程彼此交互的方式按顺序打印数字。它工作得很好,但由于某种原因,线程最终会挂起......即使我从run()返回...

另外,我正确使用旗帜还是有更好的方法?

public class Multithreading {
    public static Even even;
    public static Odd odd;

    public static void main(String[] args) throws InterruptedException{
        even = new Even();
        odd = new Odd();

        Thread a = new Thread(even);
        Thread b = new Thread(odd);
        a.start();
        b.start();
    }

    public static class Odd implements Runnable {

        public boolean running;

        public void run() {
            odd.pauseThread();
            while (!running) {}
            for (int i = 1; i <= 500; i += 2) {
                System.out.println(i);

                odd.pauseThread();

                while (!running) {
                    even.resumeThread();

                    if (i > 500) {
                        return;
                    }
                }
            }
        }

        public void pauseThread() {
            running = false;
        }

        public void resumeThread() {
            running = true;
        }
    }

    public static class Even implements Runnable {

        public boolean running;

        public void run() {
            System.out.println("Hello World");
            for (int i = 0; i <= 500; i += 2) {
                System.out.println(i);
                even.pauseThread();

                while (!running) {
                    odd.resumeThread();

                    if (i > 500) {
                        return;
                    }
                }
            }
        }

        public void pauseThread() {
            running = false;
        }

        public void resumeThread() {
            running = true;
        }
    }
}

2 个答案:

答案 0 :(得分:0)

您很快就会了解到,多线程编程非常困难,需要非常好地理解线程如何与内存以及彼此之间的交互。

从您的程序中,我可以说您需要投入更多时间来学习并发编程的基础知识。

我可以看到的主要问题:

  • evenodd个实例的静态全局和非同步使用。
  • running变量的非同步使用。
  • 如果不是线程编写一个数字,它会等待CPU密集型的紧密循环。
  • 您的线程退出条件永远不会发生:if (i > 500) {

最后一点肯定会导致至少有一个线程永远不会退出,从而产生“挂起”。但我确信其他观点也会导致竞争条件,并可能是影响因素。

我运行了你的程序,我发现除了“挂起”之外,我从来没有真正得到正确的打印结果,并且经常会得到不一致的结果。

这是一个工作程序,试图遵循您的一般设计,同时解决上述问题。阅读这是如何工作的将是你的功课。

public class Multithreading {

    public static void main(String[] args) {
        SharedData sharedData = new SharedData();
        Even even = new Even(sharedData);
        Odd odd = new Odd(sharedData);

        Thread a = new Thread(even);
        Thread b = new Thread(odd);

        a.start();
        b.start();
    }

    private static class SharedData {
        public final Object syncObject = new Object();
        public boolean evensTurn = true;
    }

    private static class Odd implements Runnable {

        private final SharedData sharedData;

        public Odd(SharedData sharedData) {
            this.sharedData = sharedData;
        }

        @Override
        public void run() {
            for (int i = 1; i <= 500; i += 2) {
                synchronized (this.sharedData.syncObject) {
                    while (this.sharedData.evensTurn) {
                        try {
                            this.sharedData.syncObject.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }

                    System.out.println(i);
                    this.sharedData.evensTurn = true;
                    this.sharedData.syncObject.notify();
                }
            }
        }
    }

    private static class Even implements Runnable {

        private final SharedData sharedData;

        public Even(SharedData sharedData) {
            this.sharedData = sharedData;
        }

        @Override
        public void run() {
            for (int i = 0; i <= 500; i += 2) {
                synchronized (this.sharedData.syncObject) {
                    while (!this.sharedData.evensTurn) {
                        try {
                            this.sharedData.syncObject.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }

                    System.out.println(i);
                    this.sharedData.evensTurn = false;
                    this.sharedData.syncObject.notify();
                }
            }
        }
    }
}

推荐阅读:The entire Java Concurrency Tutorial

答案 1 :(得分:0)

您的问题看起来像生产者/消费者问题。 请检查以下链接 http://www.codeproject.com/Tips/813407/Producer-Consumer-Problem

只需用户等待并通知线程通信。