本系列译自jakob jenkov的Java并发多线程教程,个人觉得很有收获。由于个人水平有限,不对之处还望矫正!
创建和启动线程
在java中创建一个线程如下:
Thread thread = new Thread();
调用方法start()来启动一个线程:
thread.start();
这个例子没有指定线程执行任何代码,线程将会在启动之后停止。
有两种方式指定线程应该执行什么代码。第一种方式就是创建一个Thread的子类并覆写run()方法。第二种方式就是创建一个实现Runnable接口的类。
Thread的子类
第一种方式指定线程执行什么样的代码,就是创建一个Thread的子类,并且覆写run()方法。在run()方法里的代码就是你调用start()方法后,线程要执行的代码。下面是一个创建Thread子类的例子:
public class MyThread extends Thread{
@Override
public void run(){
System.out.println("MyThread running");
}
}
为了创建并启动上面的线程,你应该这样做:
MyThread myThread = new MyThread();
myThread.start();
start()方法会在线程开始后立马返回,而不是等到run()方法执行完毕。当run()执行时,就会输出“MyThread running”;
当然,你也可以创建一个Thread的匿名子类,如下:
Thread thread = new Thread(){
@Override
public void run(){
System.out.println("Thread Running");
}
}
thread.start();
上面的例子当线程被调用时会输出文本“Thread Running".
实现Runnable接口
第二种方式指定线程应该执行什么样的代码,就是创建一个实现java.lang.Runnable接口的类。这个Runnable对象可以被Thread执行。
下面是一个实现了Runnable接口的例子:
public class MyRunnable implements Runnable{
@Override
public void run(){
System.out.println("MyRunnable running");
}
}
因为有了Thread线程执行的run()方法,将MyRunnable的一个实例传给Thread的构造方法。
Thread thread = new Thread(new MyRunnable());
thread.start();
当线程启动时,会调用MyRunnable实例中的run()方法,而不是Thread自己的run()方法。上面的例子会输出”MyRunnable running".
当然,你也可以创建一个匿名的Runnable接口实例:
Runnable myRunnable = new Runnable(){
@Override
public void run(){
System.out.println("Runnable running");
}
}
Thread thread = new Thread(myRunnable);
thread.start();
Subclass or Runnable?
没有明确的规则说这两种方式哪一种是最好的。个人倾向于实现Runnable接口。将实现Runable接口的一个实例交给Thread的实例。当由线程池来执行实现Runnable接口的线程实例时,当线程池没有空闲线程可以调试时,可以让这些线程很好的排队。但是如果执行的是实现Thread的子类的线程实例,那么将会很难做到这一点。
有时,你可能要同时实现Runnable和Thread子类。例如:创建一个Thread的线程可以执行一个或多个Runable实例,这就是线程池的实现方式。
常见的陷阱:调用run()方法而不是start()方法
当创建和启动一个线程,通常会犯的一个错误就是调用run()方法,而不是start()方法,如下:
Thread newThread = new Thread(MyRunnable());
newThread.run(); // should be start();
起初,你可能没有注意到什么,因为run()正如你期待的那样被执行了。然而,他并不是被你刚创建的线程所执行。而是被创建线程的线程执行。换句话说,就是执行上面两行代码的线程来执行的run()里的方法。调用线程的使用start()方法。
线程名称
当你创建一个线程时,你可以给这个线程指定名称。线程名可以让你和其他的线程进行区分。举个例子:
Thread thread = new Thread("New Thread"){
@override
public void run(){
System.out.println("run by:"+getName());
}
}
thread.start();
System.out.println(thread.getName());
注意,字符串“New Thread"作为一个参数传给Thread的构造器,这个字符串就是线程的名称,这个名称可以通过方法getName()来获取到,你也可以传递参数的方式给一个实现Runnable的接口的线程指定线程名称:如下
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable,"New Thread");
thread.start();
System.out.println(thread.getName());
注意。MyRunnable不是Thread的一个子类,他不能直接调用Thread的getName()方法。
Thread.currentThread()
Thread.currentThread()方法返回线程正在执行的线程。
Thread thread = Thread.currentThread();
只要获取到当前运行线程,你就可以在此基础上进行方法的调用。例如:你可以获取到当前正在执行线程的名称。
String threadName = Thread.currentThread().getName();
Java Thread example
这里有一个小例子。首先输出执行main方法的线程名称。这个线程是由JVM指定的。然后开启10个线程,并以”“+i作为他们的线程名。每个线程输出他们的名字后,然后停止。
public class ThreadExample{
public static void main(String[] args){
System.out.println(Thread.currentThread().getName());
for(int i=0;i<10;i++){
new Thread(""+i){
public void run(){
System.out.println("Thread:"+getName()+"running");
}
}.start();
}
}
}
注意。线程并不是有序执行的。也就是说线程1并不是第一个执行的线程,这是因为线程的执行原则是并行的,而不是有序的,JVM和操作系统决线程的调度顺序。当他们调度时顺序是不固定的。