多线程比较简单的方式是继承Thread类,然后覆写run()方法,在客户端程序中通过调用对象的start方法即可启动一个线程,这个是多线程程序的标准写法.
错误代码:
public class Client {
public static void main(String[] args) throws InterruptedException {
// 多线程对象
MultiThread multiThread = new MultiThread();
// 启动多线程
multiThread.start(); }
} class MultiThread extends Thread {
@Override
public void start(){
//调用线程体
run();
} @Override
public void run() {
// MultiThread do something.
while(true){
System.out.println(Thread.currentThread().getId() + "---我执行了");
}
}
}
这是一个错误的多线程应用,main方法根本没有启动一个子线程,整个应用程序中,只有一个主线程在运行,并不会创建任何其他的线程.
只要删除MultiThread类中的start方法即可.
public class Client {
public static void main(String[] args) throws InterruptedException {
// 多线程对象
MultiThread multiThread = new MultiThread();
// 启动多线程
multiThread.start(); }
} class MultiThread extends Thread {
// @Override
// public void start(){
// //调用线程体
// run();
// } @Override
public void run() {
// MultiThread do something.
while(true){
System.out.println(Thread.currentThread().getId() + "---我执行了");
}
}
}
很少有人会问,为什么不必而且不能覆写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()即可.
public class Client {
public static void main(String[] args) { }
} class MultiThread extends Thread{
@Override
public void start(){
super.start();
/*其他业务处理,但是不能调用run方法*/
} @Override
public void run(){
//MultiThread do something.
}
}
此方式虽然解决了覆写start方法的问题,但是基本上无用武之地,到目前为止还没有发现一定要覆写start方法的多线程应用.所有要求覆写start的场景,都可以通过其他的方式来实现,例如:类变量,事件机制,监听等方式.