run方法是线程的入口方法, 每次我们去创建线程时都要重写run方法, run方法执行结束即该线程结束.
class MyThread extends Thread {@Overridepublic void run() { System.out.println("run");}
}public class ThreadDemo1 {public static void main(String[] args) {Thread t = new MyThread();t.start();System.out.println("main");}
}
输出: main run 或 run main
因为线程调度不同, 所以线程执行快慢不一样.
class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("run");}
}public class ThreadDemo2 {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();Thread t = new Thread(myRunnable);t.start();System.out.println("main");}
}
public class ThreadDemo3 {public static void main(String[] args) {Thread t = new MyThread() {@Overridepublic void run() {System.out.println("run");}};t.start();System.out.println("main");}
}
public class ThreadDemo4 {public static void main(String[] args) {Thread t = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("run");}});t.start();System.out.println("main");}
}
public class ThreadDemo5 {public static void main(String[] args) {Thread t = new Thread(() -> {System.out.println("run");});t.start();System.out.println("main");}
}
class MyThread extends Thread {@Overridepublic void run() {while(true) {System.out.println("run");try { //因为sleep是静态方法,所以可以直接调用Thread.sleep(1000); //可能会出现异常, 所以要捕获} catch (InterruptedException e) {e.printStackTrace();}}}
}public class ThreadDemo1 {public static void main(String[] args) {Thread t = new MyThread();t.start();while(true) {System.out.println("main");try {Thread.sleep(1000); //单位是毫秒, 这里是1s} catch (InterruptedException e) {e.printStackTrace();}}}
}
输出:
因为线程调度不同, 所以这里打印是随机的, 这里没有体现出来.
因为线程的调度是不可控的,所以,这个方法只能保证实际休眠时间是大于等于参数设置的休眠时间的.
Thread.currentThread() 获取线程的实例
public static void main(String[] args) {Thread thread = Thread.currentThread();System.out.println(thread.getName());}
输出: main
就是让一个线程停下来, 线程终止.
本质上来说, 让一个线程终止就一个方法, 让线程的入口方法执行完.
class MyThread extends Thread {public static boolean isQuit; //设置一个成员变量, 表示标志位@Overridepublic void run() {while(!isQuit) { //通过成员变量我们可以控制while循环System.out.println("run");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("程序终止!");}public static void main(String[] args) {Thread t = new MyThread();t.start();System.out.println("main");isQuit = true; //在主线程中将标志位置为true, 影响到t线程}
}
上述代码中, 我们用的是成员变量设置标志位, 那局部变量可以吗?
我们可以试试:
显示找不到该变量, 为什么找不到呢?
按理来说线程与线程之间共用一个内存地址空间, 它们之间的变量都可以访问的, 那为什么不行呢?
其实这里和 lambda 表达式有关.
lambda 表达式中捕获的变量必须是 final 修饰的 或者是 “实际 final”(没有被final修饰, 但是代码中没有对该变量进行修改过)
再看上述代码, isQuit 在主线程中创建, 又被修改过, 所以不行.
class MyThread extends Thread {@Overridepublic void run() {//这里的Thread.currentThread()是获取当前对象的实例,也就是t//isInterrupted()得到内置标志位, 初始为falsewhile(!Thread.currentThread().isInterrupted()) {System.out.println("run");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("程序终止!");}public static void main(String[] args) {Thread t = new MyThread();t.start();try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}//interrupt() 设置标志位为truet.interrupt();}
}
当我们在调用 interrupt() 时, 如果该线程在正在阻塞中(比如正在sleep中), 此时就会把阻塞状态唤醒, 通过抛出异常的方式让sleep立即结束.
注意:
当线程处于sleep状态被唤醒时, sleep会自动把isInterrupted标志位清空(true -> false). 这就导致下次循环还是会进去, 而主线程已近结束了, 没有interrupt() 来影响标志位, 就会一直循环打印run.
这就产生了上面的输出结果.
当然, 如果sleep刚刚好结束了, 这时候我们调用interrupt(), 则直接结束循环.(这种情况是很低的)
我们可以通过添加一个break来让代码抛出异常后退出循环.
class MyThread extends Thread {@Overridepublic void run() {while(!Thread.currentThread().isInterrupted()) {System.out.println("run");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();break;}}System.out.println("程序终止!");}public static void main(String[] args) {Thread t = new MyThread();t.start();try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}t.interrupt();}
}
因为线程之间是并发执行的, 操作系统对线程的调度是无序的, 所以我们无法判断哪个线程先结束, 哪个后结束.
因此, 在Thread类里提供了一个 join 方法, 来进行线程间的等待.
比如:
t.join() 放在 main 线程里就是main线程等待 t 线程结束. 这时main线程是阻塞状态, 直到 t 执行结束main线程才会从阻塞解除, 继续执行.
例:
public class ThreadDemo5 { //使用join方法可能会有异常,所以声明一下public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {System.out.println("t1");try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}});Thread t2 = new Thread(() -> {try {t1.join(); //放在这里就是t2等待t1结束} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t2");});//首先创建两个线程t1.start();t2.start();t2.join(); //这里main线程等待t2结束System.out.println("main");}
}
首先main线程等待 t2 线程执行结束, 而 t2 线程在等待 t1 线程结束, 所以就出现上面结果.