多线程比较简单的方式是继承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的场景,都可以通过其他的方式来实现,例如:类变量,事件机制,监听等方式.