1.概述
在上一篇文章Java多线程设计(一)由浅入深介绍进程与线程我已结介绍了线程以及与线程相关的知识,现在就开始正式说一下Java中的线程的基本知识。
2.线程的启动
其实我们最经常看到的线程就主线程,就是做main
方法中的任务,但是它是被虚拟机启动的,下面就来看看我们自定义的线程是怎么启动的。
自定义线程有两种方法可以启动
- (1)利用Thread类的子类实例启动线程
- (2)利用Runnable接口的实现类实例启动线程
下面我就分别介绍一下这两种方式
2.1 利用Thread类的子类
大家都知道Java的宗旨的万物皆对象,线程应该也是一类东西,应该有个类来代表它,这个类就是Thread
类,Thread类的全限定名是java.lang.Thread
。这个类里面有两个很重要的方法,分别是run()
方法和start()
方法。
首先来说一下run()
方法,自定义线程类在继承Thread
类后要重写一下这个方法,因为这个方法就是线程任务所在的方法,run()
方法结束时,线程也就结束了。例如下面这个类
public class MyThread extends Thread{
private String msg;
public MyThread(String msg) {
this.msg = msg;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + msg);
}
}
}
其中Thread.currentThread().getName()
是获取当前运行该方法的线程的名字。但是光有run()
方法还不行,它里面放的只是任务,并不是启动线程的方法,如果你直接在main
方法中调用run()
方法,如
MyThread myThread = new MyThread("hello");
myThread.run();
结果是在控制台输出100行main:hello
。
启动线程要使用start()
方法,这个方法是从Thread
类继承过来的,直接调用这个方法就会启动一个线程,执行run()
方法中的代码,如
MyThread myThread = new MyThread("hello");
myThread.start();
结果输出100行Thread-0:hello
,其中Thread-0
就是该线程的名称。
这样子,一个线程的启动到结束就完成了。
2.2 利用Runnable接口的实现类
在Thread
类的构造方法中有一个public Thread(Runnable target)
构造方法,接受一个Runnable
类型的对象,这个Runnable
是一个接口,说明最终传进来的会是它的实现类,其中说明了对象target
中的run()
方法会被调用。
那么我们来看看Runnable
接口,它里面只声明了一个方法,如下
public interface Runnable {
public abstract void run();
}
实现Runnable
接口的类必须实现run()
方法,那我可以把上面的MyThread
类实现Runnable
接口,代码如下
public class MyThread implements Runnable{
private String msg;
public MyThread(String msg) {
this.msg = msg;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ":" + msg);
}
}
}
你可以发现其它的都没变,就是将extends Thread
改为implements Runnable
了。
则启动该线程的代码如下
public class Main {
public static void main(String[] args) {
Runnable myThread = new MyThread("hello");
Thread thread = new Thread(myThread);
thread.start();
}
}
执行结果还是输出100行Thread-0:hello
。
这样子,利用Runnable接口的实现类启动线程就搞定了。
3. 线程的暂时停止
线程启动好了,一直在运行,如果我们让它“休息”一下,也就是暂时停止线程的执行。
使用Thread
类的sleep
方法可以暂时停止线程的执行操作。sleep在英文中就是“睡着”的意思,所以我们经常会说让线程睡一下。
执行下面的语句,就可以让线程(注意,是执行该语句的线程)暂时停止2000ms(即2s,ms为毫秒,1s=10^3ms)。
Thread.sleep(2000);
那么现在我就可以写一个程序,让它每2000ms也就是2s输出一句”hello”
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println("hello");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
}
}
输出结果是10行hello
,但是每行输出时间间隔为2s。其中Thread.sleep(2000);
在try-catch
块中是因为sleep
方法可能抛出一个InterruptedException
异常。
如果我们要让线程暂停的时间更加精确点的话,可以使用ns(ns为纳秒,1s=10^9ns)为单位,如下面这样调用
Thread.sleep(2000,1000);
则线程的睡眠时间会是2000ms+1000ns
。