java创建子线程为什么要有两种方法?

java创建子线程为什么要有两种方法?
马克-to-win:通过以下两种方法创建子线程:1)声明一个Thread类的子类。 2)实现runnable接口。java的官方文档也没强调这二者有什么区别。马克-to-win:笔者认为,既然java只允许继承一个类,如果你这个类本身就是某个类的子类,那你要想创建子线程,你就只能实现runnable这个接口。
马克- to-win:马克 java社区:防盗版实名手机尾号: 73203。



例:1.3.2-本章源码
class ThreadMark_to_win extends Thread {
    public void run() {
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程i = " + i);
        }
    }
}
public class Test {
    public static void main(String[] args)  {
        Thread t = new ThreadMark_to_win();
        t.start();
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("主线程i = " + i);
        }
    }
}
输出结果:
主线程i = 0
子线程i = 0
主线程i = 1
子线程i = 1
主线程i = 2
子线程i = 2

马克-to-win:对于以上例子的解释:1)根据语法:在start以后,子线程被启动,run方法被运行,与此同时cpu继续执行主线程的for循环,这就是多线程的奥妙之处,所以当我们看结果时, 我们看到主线程和子线程交替输出,如果子线程被挡住了,主线程是不受干扰的,这也是多线程的奥妙之处。马克-to-win:在程序中,如果我不让它睡觉停顿一秒钟。CPU来不及切换就执行完了,大家看不出效果。大家还以为是顺序执行的呢!其实是主子线程交替执行的。2)马克-to-win:当我的ThreadMark_to_win继承了 Thread以后,为什么一start,run 就被运行,我们可以猜一猜sun公司是怎么实现的这一切?其实这就用到了我们前面学过的多态,当父类指针指向子类时,当子类 ThreadMark_to_win没有start方法时, 就执行父类Thread的start方法, Thread的start方法说,执行子类run方法,(我们的ThreadMark_to_win正好编了run方法)而且继续主线程的下一句,于是就是我们前面看到的并发效果。

马克-to-win:更有甚者,我们观察下面的两个例子会发现:甚至当子线程抛出异常,子线程戛然停止崩溃时,主线程都不会受影响继续运行,整个程序也照常运行,不会崩溃。反之亦然,主线程戛然停止崩溃时,整个程序不受影响,子程序照常运行。

为什么抛出异常,别的线程还是能运行呢?想象一下程序执行的过程就明白了。jvm一句一句的向下执行,当它发现异常时,它对别的线程,还是该干什么干什么。注意现在是你的程序出现问题,jvm一点问题都没有,所以它还能正常该干什么干什么。(见下面的例子)




例:1.3.2_1-本章源码
class ThreadMark_to_win extends Thread {
    public void run() {
        for (int i = 0; i < 7; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程i = " + i);
        }
    }
}
public class Test {
    public static void main(String[] args)  {
        Thread t = new ThreadMark_to_win();
        t.start();
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("主线程i = " + i);
        }
        throw new ArithmeticException("divide by 0");
//后面不能再加任何语句了,会报unreachable compile error的
    }
}
输出结果:
主线程i = 0
子线程i = 0
主线程i = 1
子线程i = 1
子线程i = 2
主线程i = 2Exception in thread "main"
java.lang.ArithmeticException: divide by 0
    at Test.main(Test.java:25)
子线程i = 3
子线程i = 4
子线程i = 5
子线程i = 6




例:1.3.2_2-本章源码
class ThreadMark_to_win extends Thread {
    public void run() {
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程i = " + i);
        }
        throw new ArithmeticException("divide by 0");
    }
}
public class Test {
    public static void main(String[] args)  {
        Thread t = new ThreadMark_to_win();
        t.start();
        for (int i = 0; i < 6; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("主线程i = " + i);
        }
    }
}

输出结果:
子线程i = 0
主线程i = 0
子线程i = 1
主线程i = 1
子线程i = 2
Exception in thread "Thread-0" java.lang.ArithmeticException: divide by 0
    at ThreadMark_to_win.run(Test.java:11)
主线程i = 2
主线程i = 3
主线程i = 4
主线程i = 5


下面介绍第二种方法创建子线程。





例:1.3.3-本章源码

class CommonClassMark_to_win implements Runnable {
    public void run() {
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程i = " + i);
        }
    }
}
public class Test {
    public static void main(String[] args)  {
        CommonClassMark_to_win cc = new CommonClassMark_to_win();
        Thread t=new Thread(cc);
        t.start();
        for (int i = 0; i < 3; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("主线程i = " + i);
        }
    }
}
输出结果:
主线程i = 0
子线程i = 0
子线程i = 1
主线程i = 1
主线程i = 2
子线程i = 2

后续:
马克-to-win:刚这个例子的CommonClassMark_to_win只是个普通的类,并没有start方法,所以只能靠着Thread t=new Thread(cc);和线程扯上关系。输出结果和第一种启动线程的方法是一样的。