原文链接:http://tutorials.jenkov.com/java-concurrency/creating-and-starting-threads.html
摘要:这是翻译自一个大概30个小节的关于Java并发编程的入门级教程,原作者Jakob Jenkov,译者Zhenning Lang,转载请注明出处,thanks and have a good time here~~~(希望自己不要留坑)
Java 线程如 Java 中其他对象一样也是一个对象。线程是 java.lang.Thread 的实例,或者是其子类的实例,Java 线程用来执行代码。
1 Java 线程视频教程
下面的链接是一个 Java 线程的视频教程
https://www.youtube.com/embed/9y7l6QHpoQI
2 创建并启动线程
Java 中像这样创建一个线程:
Thread thread = new Thread();
为了使这个线程启动,需要调用其 start() 方法,
thread.start();
上面的例子没有指定这个线程需要执行的代码,所以这个线程将在启动后立刻结束。
有两种方法来指定线程需要执行的代码。第一种是创建 Thread 的子类并覆盖其 run() 方法,第二种方法是向 Thread 的构造函数传递一个实现了 Runnable(java.lang.Runnable) 接口的对象,下面将分别予以介绍。
2.1 创建Thread 的子类
第一种指定线程执行代码的方法是创建一个 Thread 类的子类并覆盖其 run() 方法,run() 的内部的代码就是调用 start() 后所执行的代码,如下例所示:
public class MyThread extends Thread {
public void run(){
System.out.println("MyThread running");
}
}
创建并启动上面线程的代码如下:
MyThread myThread = new MyThread();
myTread.start();
start() 函数被调用后,当线程开始将立刻返回,而不会等到 run() 中的代码被执行完毕。run() 方法将在新线程中被执行,就好像在一个独立的 CPU 中。上例中 run() 方法将打印“MyThread running”。
也可以使用匿名内部类来实现上面的内容:
Thread thread = new Thread(){
public void run(){
System.out.println("Thread Running");
}
}
thread.start();
2.2 实现 Runnable 接口
第二种指定多线程执行代码的方法是创建一个实现 java.lang.Runnable 接口的类。Runnable 对象可以被线程执行。下面是一个简单示例:
public class MyRunnable implements Runnable {
public void run(){
System.out.println("MyRunnable running");
}
}
为了让 run() 方法中的代码被线程执行,需要将 MyRunnable 类的实例传给 Thread 的构造函数,如下所示:
Thread thread = new Thread(new MyRunnable());
thread.start();
当 thread 启动时,它会调用 MyRunnable 类的实例的 run() 方法,而不是其自己的 run() 反复。上例会打印“MyRunnable running”。
也可以以匿名内部类的方式实现 Runnable 接口,如下所示:
Runnable myRunnable = new Runnable(){
public void run(){
System.out.println("Runnable running");
}
}
Thread thread = new Thread(myRunnable);
thread.start();
3 常见错误:错把 run() 方法当做 start() 方法
当创建和启动新线程时一个常见的错误是调用 run() 方法来启动线程,而没有调用 start() 方法,如下:
Thread newThread = new Thread(MyRunnable());
newThread.run(); //should be start();
虽然一开始一切看起来都很正常,运行结果也符合你的预期,但代码并没有在新线程中执行,而是在创建新线程的线程中被执行了。换言之就是没有创建新的线程。
4 线程名
当你创建一个 Java 线程时你可以给其取一个名字,用于帮助你区分不同的线程。举例来说,如果多个线程都调用 System.out,那么很难判断究竟是哪个线程进行了输出。下面是给线程指定名称的例子:
Thread thread = new Thread("New Thread") {
public void run(){
System.out.println("run by: " + getName());
}
};
thread.start();
System.out.println(thread.getName());
上面传给 Thread 构造函数的字符串“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 的子类,所以 MyRunnable 类内的 run() 方法并不能调用 getName() 方法(当然,可以通过 Thread.currentThread().getName() 实现这个功能)。
5 Thread.currentThread()
Thread.currentThread() 方法返回执行 Thread.currentThread() 函数的线程的实例引用。通过这种方法可以在代码中获得当前线程的 Thread 对象,如下例所示:
Thread thread = Thread.currentThread();
一旦获得了 Thread 对象的引用,就可以调用其中的方法。下例展示了如何获得当前线程的名称:
String threadName = Thread.currentThread().getName();
6 实例
下面是一个实例。首先打印出 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,2,3, … 的顺序被创建和启动的,但其执行顺序却可能不是这个顺序。例如线程 1 可能不是第一个执行输出的线程。这是因为本质上这些线程是并行而非顺序执行的。JVM 和/或者操作系统将决定线程的执行顺序。