首页 > 技术文章 > [改善Java代码]不推荐覆写start方法

DreamDrive 原文

多线程比较简单的方式是继承Thread类,然后覆写run()方法,在客户端程序中通过调用对象的start方法即可启动一个线程,这个是多线程程序的标准写法.

错误代码:

 1 public class Client {
 2     public static void main(String[] args) throws InterruptedException {
 3         // 多线程对象
 4         MultiThread multiThread = new MultiThread();
 5         // 启动多线程
 6         multiThread.start();
 7 
 8     }
 9 }
10 
11 class MultiThread extends Thread {
12      @Override
13      public void start(){
14          //调用线程体
15          run();
16      }
17 
18     @Override
19     public void run() {
20         // MultiThread do something.
21         while(true){
22             System.out.println(Thread.currentThread().getId() + "---我执行了");
23         }
24     }
25 }

这是一个错误的多线程应用,main方法根本没有启动一个子线程,整个应用程序中,只有一个主线程在运行,并不会创建任何其他的线程.

只要删除MultiThread类中的start方法即可.

 1 public class Client {
 2     public static void main(String[] args) throws InterruptedException {
 3         // 多线程对象
 4         MultiThread multiThread = new MultiThread();
 5         // 启动多线程
 6         multiThread.start();
 7 
 8     }
 9 }
10 
11 class MultiThread extends Thread {
12     // @Override
13     // public void start(){
14     // //调用线程体
15     // run();
16     // }
17 
18     @Override
19     public void run() {
20         // MultiThread do something.
21         while(true){
22             System.out.println(Thread.currentThread().getId() + "---我执行了");
23         }
24     }
25 }

 很少有人会问,为什么不必而且不能覆写start方法,仅仅就是因为"多线程应用就是这样写的"这个原因?

说明这个原因要看Thread类的源代码.

public synchronized void start() {
    //判断线程状态,必须是未启动的状态
    if (threadStatus != 0)
        throw new IllegalThreadStateException();
    //加入线程组中
    group.add(this);
    //分配占内存,启动线程,运行run方法
    start0();
    //在启动前设置了停止状态
    if(stopBeforeStart){
        stop0(throwableFromStop)
    }
}
//本地方法
private native void start0();

这里的关键是本地方法start0,它实现了启动线程,申请栈内存,运行run方法,修改线程状态等职责,线程管理和栈内存管理都是由JVM负责的,如果覆盖了start方法,也就是撤销了线程管理和栈内存管理的能力,这样如何启动一个线程呢?

事实上,不需要关注线程和栈内存的管理,只需要编码者实现多线程的业务逻辑即可(即run方法体),这也是JVM比较聪明的地方,简化多线程应用.

那如果非要覆写start方法,如何处理?这确实是一个罕见的要求,但是覆写也很容易,只要在start的方法上加上super.start()即可.

 1 public class Client {
 2     public static void main(String[] args) {
 3         
 4     }
 5 }
 6 
 7 
 8 class MultiThread extends Thread{
 9     @Override
10     public void start(){
11         super.start();
12         /*其他业务处理,但是不能调用run方法*/
13     }
14     
15     @Override
16     public void run(){
17         //MultiThread do something.
18     }
19 }

此方式虽然解决了覆写start方法的问题,但是基本上无用武之地,到目前为止还没有发现一定要覆写start方法的多线程应用.所有要求覆写start的场景,都可以通过其他的方式来实现,例如:类变量,事件机制,监听等方式.

推荐阅读