0

我写了一个代码,如果被测试的数字是一个快乐的数字,则打印 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 不是。

4

2 回答 2

1

当我阅读您的程序时,第一次通过主循环时,IsHappy将分叉一个新线程,并将其num设置为1. 在IsHappy.run()方法中,if numis1立即退出。

while(!out && num != 1)

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

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

这不是你所期望的吗?我认为您应该学习如何使用调试器。这是一个关于如何在 Eclipse 中调试程序的好教程。

如果7处理了数字,则该IsHappy.run()方法将旋转,一遍又一遍地 设置num49( )。然后会看到它还活着并且会调用并且会打印。7*7mainIsHappyIsHappy.Exit()0

如果21处理了数字,则该IsHappy.run()方法将旋转,一遍又一遍地 设置num5( )。将再次线程和打印。2*2+1*1mainExit()0

所以我猜你的输出是:

11
0
0

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

关于您的代码的其他一些评论。这可能是测试代码,所以没关系,但要学究:

  • 永远不要捕获并丢弃异常(请参阅您的IOException捕获)。至少在一个空的 catch 块中添加注释,解释为什么你不关心异常。
  • 您的线程正在旋转进行计算。这显然不是对资源的良好利用。
  • 您没有关闭任何输入流或阅读器。在处理这些问题时,请始终使用 try/finally。
  • Exit()方法应以小写字母开头。该方法的更好名称是stop.
于 2012-09-29T23:42:46.430 回答
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)));
    }
}

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

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,您将不会进入检查 num 的值并基于哪个中断主线程的 if 条件。

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 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
于 2012-09-29T23:58:02.327 回答