主线程没有被打断

时间:2012-09-29 23:35:02

标签: java multithreading

我编写了一个代码,如果被测试的数字是一个满意的数字,则打印1,否则为0。

class Ishappy extends Thread {
    private Integer num;
    private Thread main;
    private volatile boolean out = false;

    Ishappy(int i, Thread main) {
        this.main = main;
        num = i;
    }

    void Exit() {
        out = true;
    }

    @Override
    public void run() {
        while(!out && num != 1) {
            if(num == 1) {
                main.interrupt();
                break;
            }

            String s = num.toString();
            int temp = 0;
            for(int i = 0 ; i < s.length(); i++) {
                int x = Integer.parseInt(s.substring(i, i+1));
                temp += x*x;
            }
            num = temp;
        }
    }
}

public class Happy_numbers {
    public static void main(String[] args) {
        byte path[] = null;

        String s = "d:\\data.txt";

        try(FileInputStream fin = new FileInputStream(s)) {
            InputStreamReader in = new InputStreamReader(fin);
            BufferedReader br = new BufferedReader(in);
            s = br.readLine();
            int num;
            while(s != null) {
                num = Integer.parseInt(s);

                Ishappy ishappy = new Ishappy(num,Thread.currentThread()); 
                ishappy.start();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    System.out.println(1);
                    continue;
                }
                if(ishappy.isAlive()) {
                    ishappy.Exit();
                    System.out.println(0);
                } else
                    System.out.println(11);

                s = br.readLine();
            }
        } catch (FileNotFoundException ex) {
            System.out.println("File not found.");
        }catch(IOException ex){
        }
    }
}

但上面的代码总是打印11表示一个快乐的数字,这意味着main永远不会被打断。怎么了?

data.txt的内容是

1
7
22

其中1和7是幸福数字而22则不是。

2 个答案:

答案 0 :(得分:1)

当我阅读你的程序时,第一次通过主循环,一个新的IsHappy线程将被分叉,num设置为1。在IsHappy.run()方法中,如果num1,则会立即退出。

while(!out && num != 1)

main将休眠,然后打印11,因为线程不再运行。

if(ishappy.isAlive()) {
    ishappy.Exit();
    System.out.println(0);
} else
   System.out.println(11);

这不是你所期望的吗?我想你应该学习如何使用调试器。这是一个关于如何debug your program in Eclipse的好教程。

如果处理了号码7,那么IsHappy.run()方法将会旋转,将num反复设置为497*7)。然后,main会看到IsHappy仍然有效,并会致电IsHappy.Exit()并打印0

如果处理了号码21,那么IsHappy.run()方法将会旋转,将num反复设置为52*2+1*1)。 main将再次Exit()该主题并打印0

所以我猜你的输出是:

11
0
0

main线程永远不会被中断,因为如果while num == 1循环将阻止它运行。

关于您的代码的其他一些评论。这可能是测试代码,所以无关紧要,但要迂腐:

  • 永远不要抓住并抛弃异常(请参阅IOException捕获)。至少在空的catch块中添加注释,解释为什么你不关心异常。
  • 你的线程正在旋转进行计算。这显然不是很好地利用资源。
  • 您没有关闭任何输入流或读者。处理这些时总是使用try / finally。
  • Exit()方法应以小写字母开头。该方法的更好名称是stop

答案 1 :(得分:0)

我认为这里不需要线程,如果数字平方的总和等于1,则快乐的数字很高兴。如果序列包含已经测试过的数字。刚刚终止。

来自维基百科的

  

如果n不满意,那么它的序列不会转到1.相反,它会在循环中结束。

public class Happy_numbers {        
    static int[]SQUARES={0,1,4,9,16,25,36,49,64,81};
    public static boolean is_happy(int n){
        return is_happy(n, new HashSet<Integer>());
    }
    public static boolean is_happy(int n, Collection<Integer> sofar){
        if(n==1) return true;
        else if(sofar.contains(n)) return false;

        sofar.add(n);

        if(n<10) {
            return is_happy(SQUARES[n], sofar);
        }

        char[]digits=String.format("%s", n).toCharArray();
        int s = 0;
        for(char c:digits){
            s+= SQUARES[Integer.valueOf(String.format("%s", c))];
        }

        return is_happy(s, sofar);
    }
    public static void main(String[]args){
        Collection<Integer> c1 = Arrays.asList(
                1, 7, 10, 13, 19, 23, 28, 31, 32, 44, 49, 68, 70, 79, 82, 86, 91, 94, 97, 
                100, 103, 109, 129, 130, 133, 139, 167, 176, 188, 190, 192, 193, 203, 208, 
                219, 226, 230, 236, 239, 262, 263, 280, 291, 293, 301, 302, 310, 313, 319, 
                320, 326, 329, 331, 338, 356, 362, 365, 367, 368, 376, 379, 383, 386, 391, 
                392, 397, 404, 409, 440, 446, 464, 469, 478, 487, 490, 496 );
        Collection<Integer> c2 = new ArrayList<Integer>(c1.size());
        long t = System.currentTimeMillis();
        int c = 1;
        for(int i=0;i<500;i++){
            if(is_happy(i)) {
                System.out.print(i+", ");
                if(c++ % 20 == 0) System.out.println();
                c2.add(i);
            }

        }
        t = System.currentTimeMillis()-t;
        System.out.println("\nTIME : " + t);
        System.out.println("Got them all < 500 : " + (c2.containsAll(c1) && c1.containsAll(c2)));
    }
}

通过使用地图或任何缓存技术也可以进一步改进,因此如果数字很开心并且您之前已经计算过这个数字,则无需再次执行相同的操作。来自wikipediea,

  

500以下的满意数字是:   1,7,10,13,19,23,28,31,32,44,49,68,70,79,82,86,91,94,97,100,103,109,   129,130​​,133,139,167,176,188,190,192,193,203,208,219,226,230,236,239,262,   263,280,291,293,301,302,310,313,319,320,326,329,331,338,356,362,365,367,368,   376,379,383,386,391,392,397,404,409,440,446,464,469,478,487,490,496   (OEIS中的序列A007770)。

以上代码需要435才能获得500以下的所有满意数字。

1, 7, 10, 13, 19, 23, 28, 31, 32, 44, 49, 68, 70, 79, 82, 86, 91, 94, 97, 100, 
103, 109, 129, 130, 133, 139, 167, 176, 188, 190, 192, 193, 203, 208, 219, 226, 230, 236, 239, 262, 
263, 280, 291, 293, 301, 302, 310, 313, 319, 320, 326, 329, 331, 338, 356, 362, 365, 367, 368, 376, 
379, 383, 386, 391, 392, 397, 404, 409, 440, 446, 464, 469, 478, 487, 490, 496, 
TIME : 435
Got them all < 500 : true

因此,我对您的代码进行了一些更改,以便记住到目前为止计算的内容,至少是当前的数字。

public class Happy_numbers {

    static class Ishappy extends Thread {
        private Integer num;
        private Thread main;
        private volatile boolean out = false;

        private boolean unhappy = false;

        Ishappy(int i, Thread main) {
            this.main = main;
            num = i;
        }

        public boolean isUnhappy() {
            return unhappy;
        }

        void Exit() {
            out = true;
        }

        @Override
        public void run() {
            Set<Integer> sofar = new HashSet<Integer>();
            while(!out && num != 1) {
                unhappy = sofar.contains(num);
                if(num == 1 || unhappy) {
                    main.interrupt();
                    break;
                }

                sofar.add(num);

                String s = num.toString();
                int temp = 0;
                for(int i = 0 ; i < s.length(); i++) {
                    int x = Integer.parseInt(s.substring(i, i+1));
                    temp += x*x;
                }
                num = temp;
            }
        }
    }

    public static void main(String[] args) throws Exception{
        byte path[] = null;

        String s = "./data.txt";

        FileInputStream fin = new FileInputStream(s);
        InputStreamReader in = new InputStreamReader(fin);
        BufferedReader br = new BufferedReader(in);
        int num;
        while((s = br.readLine()) != null) {
            num = Integer.parseInt(s);

            Ishappy ishappy = new Ishappy(num,Thread.currentThread()); 
            ishappy.start();
            ishappy.join();
            if(ishappy.isUnhappy()){
                System.out.println("Number ["+num+"] is not happy");
            }else{
                System.out.println("Number ["+num+"] is happy");
            }
        }
        br.close();
        in.close();
        fin.close();
    }
}

,输出

Number [1] is happy
Number [7] is happy
Number [22] is not happy

修改

我找到了主线程不会被打断的原因。

在主while循环中,你检查num是否为1,如果是1,你将不会得到if条件,它检查num的值并根据哪个中断主线程。

public class Happy_numbers {
    public static void main(String[] args) throws IOException{

        String s = "./data.txt";

        FileInputStream fin = new FileInputStream(s);
        InputStreamReader in = new InputStreamReader(fin);
        BufferedReader br = new BufferedReader(in);
        int num;
        while((s = br.readLine()) != null) {
            num = Integer.parseInt(s);

            Ishappy ishappy = new Ishappy(num,Thread.currentThread()); 
            ishappy.start();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                System.out.println(1);
                continue;   // here is another problem, infinit loop
            }
            if(ishappy.isAlive()) {
                ishappy.Exit();
                System.out.println(0);
            } else
                System.out.println(11);

        }
        br.close();
        in.close();
        fin.close();
        System.out.println("DONE");
    }
}

这是Ihappy class

class Ishappy extends Thread {
    private volatile Integer num;
    private Thread main;
    private volatile boolean out = false;

    Ishappy(int i, Thread main) {
        this.main = main;
        num = i;
    }

    void Exit() {
        out = true;
    }

    @Override
    public void run() {
        while(!out) {   /// <- here was the problem
            if(num.intValue() == 1) { // since this condition will break out
                main.interrupt();     // of the loop, you do not need it in the
                break;                // while condition
            }

            String s = num.toString();
            int temp = 0;
            for(int i = 0 ; i < s.length(); i++) {
                int x = Integer.parseInt(s.substring(i, i+1));
                temp += x*x;
            }
            num = temp;
        }
    }
}

,输出

1
1
0
DONE