start()
启动线程,运行 run 方法中的代码
注意
- start 方法只是让 线程进入了 就绪,而不是马上运行,需要等待CPU的时间片
- 一个线程只能调用一次 start,否则会出现 IllegalThreadStateException
代码实例
Thread t1=new Thread(() -> {
System.out.println("线程1 运行");
});
Thread t2=new Thread(() -> {
System.out.println("线程2 运行");
});
t1.start();
t2.start();
上面代码的的运行结果可能是
线程2 运行
线程1 运行
虽然 线程1 比 线程2 更早进入就绪态,但是 线程2 比 线程1 更早获取到CPU时间片,因此更早执行
run()
在该方法中定义线程要完成的任务
以下是Runnable接口的源码
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
可以看到加了 @FunctionalInterface ,是函数式接口,并且只有一个run方法
我们看Thread源码,发现Thread的run方法就是来源于 Runnable 接口
public class Thread implements Runnable
我们可以直接重写 Thread 中的run方法,比如
Thread t3 = new Thread(){
@Override
public void run() {
System.out.println("线程3 运行");
}
};
t3.start();
也可以继承 Thread 类后再重写
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread...run...");
}
public static void main(String[] args) {
// 创建MyThread对象
MyThread t1 = new MyThread() ;
MyThread t2 = new MyThread() ;
}
}
观察Thread源码,发现存在Runnable属性
/* What will be run. */
private Runnable target;
因此,也可以在构造 Thread 对象时传递 Runnable 参数,则线程启动后会调用 Runnable 中的 run 方法
代码实例
Thread t1=new Thread(() -> {
System.out.println("线程1 运行");
});
Thread t2=new Thread(() -> {
System.out.println("线程2 运行");
});
t1.start();
t2.start();
在上面的代码中,调用的 Thread 构造方法,如下
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
我们使用Lambda表达式实现了Runnable接口的run方法
可以用一句话概括,如果 Thead 类上的Runnable属性不为null,则执行该Runnable属性的run方法,否则执行Thread自己的run方法
join() 和 join(long n)
join() -- 等待线程运行结束
join(long n) -- 等待线程运行结束,最多等待 n 毫秒
Thread t3 = new Thread(){
@Override
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t3.start();
t3.join();
System.out.println("main 继续执行");
执行上面的代码会发现,无论如何都会等待至少10秒才会输出 "main 继续执行"
sleep(long n)
sleep是Thread的静态方法
作用是:让当前执行的线程休眠n毫秒,休眠时让出 cpu 的时间片给其它线程
上面的代码实例就已经使用到 sleep 方法
哪个线程调用了 Thread.sleep(10000) ,哪个线程睡眠
比如在上面的代码实例中,线程3 会睡眠 10 秒,而 主线程 并不会睡眠
另外
- 睡眠结束后的线程未必会立刻得到执行
- 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
- 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep来获得更好的可读性 (TimeUnit 的 sleep方法与 Thread的sleep方法相同)
interrupt()
interrupt 打断线程
无论线程处在阻塞(sleep、wait、join)还是运行状态,都可以被打断
如果被打断线程正在 sleep、wait、join 会导致被打断的线程抛出 InterruptedException,并清除 打断标记 ;如果打断的正在运行的线程,则会设置 打断标记 ;
interrupt 是非静态方法,需要打断哪个线程,就调用那个线程的 interrupt方法
代码实例
private static void test1() throws InterruptedException {
Thread t1 = new Thread(()->{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t1");
t1.start();
Thread.sleep(500);
t1.interrupt();
}
yield()
sleep 能使线程让出 CPU时间片
而 yield方法 同样 能使线程让出CPU时间片
但是 调用 yield 方法时,线程不一定会马上让出CPU,这取决于操作系统的任务调度器
而且 sleep 方法是让线程从 Running 进入 Timed Waiting 状态(阻塞),yield是让当前线程从 Running 进入 Runnable 就绪状态
yield方法也是个静态方法
currentThread()
public static native Thread currentThread();
可以看到currentThread也是个静态方法,并且返回值是Thread
用法 -- 在哪个线程中调用 Thread.currentThread ,就会返回当前线程的 Thread 对象,有点类似 this 关键字