1.创建线程
方法1继承Thread类
class MyThread extends Thread{ @Override public void run() { System.out.println("Thread1"); } } public class Demo1 { public static void main(String[] args) { MyThread t = new MyThread(); t.start(); //线程开始运行 } }
方法2实现Runnable接口
class MyRunnable implements Runnable{ @Override public void run() { System.out.println("Thread2"); } } public class Demo2 { public static void main(String[] args) { Thread t = new Thread(new MyRunnable()); t.start(); } }
方法3匿名内部类创建Thread子类对象
public class Demo3 { public static void main(String[] args) { Thread t = new Thread(){ @Override public void run() { System.out.println("Thread3"); } }; t.start(); } }
方法4匿名内部类创建Runnable子类对象
public class Demo4 { public static void main(String[] args) { Thread t = new Thread(new Runnable() { @Override public void run() { System.out.println("Thread4"); } }); t.start(); } }
方法5lambda表达式创建Runnable子类对象
public class Demo5 { public static void main(String[] args) { Thread t = new Thread(() ->{ System.out.println("Thread5"); }); t.start(); } }
2.线程中断
一个线程调用start方法后,才真的在操作系统的底层创建出一个线程,一旦进入到工作状态,不完成整个线程的任务是不会结束的。但是在一个线程执行的过程中,急需停止他,我们该怎么做呢?目前有两种常见的方式:
- 通过共享的标记来进行沟通
- 调用interrupt方法来通知
示例1:使用自定义的变量作为标志位(需要加上volatile关键字)
public class ThreadDemo { private static class MyRunnable implements Runnable { public volatile boolean isQuit = false; @Override public void run() { while (!isQuit) { //线程执行的任务 System.out.println("haha"); } } } public static void main(String[] args) throws InterruptedException { MyRunnable target = new MyRunnable(); Thread thread = new Thread(); thread.start(); Thread.sleep(10 * 1000); System.out.println(Thread.currentThread().getName() + ": 紧急停止当前线程"); target.isQuit = true; } }
当进程运行10次后,将标志位改为true,即可停止线程
示例2:使用Thread.interrupted()或者Thread.currentThread().isInterrupted()代替自定义标志位
public class ThreadDemo { private static class MyRunnable implements Runnable { public volatile boolean isQuit = false; @Override public void run() { // 两种方法均可以 while (!Thread.interrupted()) { //while (!Thread.currentThread().isInterrupted()) { //线程执行的任务 System.out.println("haha"); } } } public static void main(String[] args) throws InterruptedException { MyRunnable target = new MyRunnable(); Thread thread = new Thread(); thread.start(); Thread.sleep(10 * 1000); System.out.println(Thread.currentThread().getName() + ": 紧急停止当前线程"); thread.interrupt(); } }
3.线程等待
有时候,我们需要等待一个线程结束后,才能进行下一步工作,例如:一个线程的工作是买饭,另外一个线程工作是吃饭,我们只有在买完饭后才能考虑要不要吃饭。这时候我们需要一个方法明确等待线程的结束。
public class ThreadDemo { public static void main(String[] args) throws InterruptedException { Runnable target = () -> { for (int i = 0; i < 3; i++) { try { System.out.println(Thread.currentThread().getName() + ": 我还在工作!"); Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + ": 我结束了!"); }; Thread thread1 = new Thread(target, "李四"); Thread thread2 = new Thread(target, "王五"); System.out.println("先让李四开始工作"); thread1.start(); thread1.join(); System.out.println("李四工作结束了,让王五开始工作"); thread2.start(); thread2.join(); System.out.println("王五工作结束了"); } }
代码的执行结果是:李四工作结束后,王五再进行工作,然后王五工作也结束。join方法可以保证让上一个线程执行结束后再执行后面的代码。我们可以看看将join方法注释前后的区别:
注释前:
注释后:
我们可以看出来,如果没有join方法,就相当于是两个线程并行工作了。
4.线程休眠
我们要知道线程的调度是不可控的,所以我们只能保证实际休眠时间是大于等于参数设置的休眠时间的
public class ThreadDemo { public static void main(String[] args) throws InterruptedException { System.out.println(System.currentTimeMillis()); Thread.sleep(3 * 1000); System.out.println(System.currentTimeMillis()); } }
其中Thread.sleep(3*1000),就是休眠时间为3秒
5.线程的状态
线程的状态是一个枚举类型Thread.State
public class ThreadState { public static void main(String[] args) { for (Thread.State state : Thread.State.values()) { System.out.println(state); } } }
- NEW:安排了工作,还未开始行动
- RUNNABLE:可工作的,又可以分为正在工作中和即将开始工作
- BLOCKED:表示排队等着其他事情
- WAITING:表示排队等着其他事物
- TIMED_WAITING:表示排队等着其他事物
- TERMINATED:工作完成
说明:当Thread实例化一个对象后,该线程就处于NEW状态,使用start方法,线程就会进入RUNNABLE状态,此时执行wait、join等方法会进入到WAITING、TIMED_WAITNG或者BLOCKED状态,若在RUNNABLE状态一直正常执行,执行完成后就是TERMINATED状态
观察1:NEW、RUNNABLE、TERMINATED状态的转换
public class ThreadStateTransfer { public static void main(String[] args) throws InterruptedException { Thread t = new Thread(() -> { for (int i = 0; i < 1000_0000; i++) { } }, "李四"); System.out.println(t.getName() + ": " + t.getState());; t.start(); while (t.isAlive()) { System.out.println(t.getName() + ": " + t.getState());; } System.out.println(t.getName() + ": " + t.getState());; } }
观察2:WAITING、BLOCKED、TIMED_WAITING状态的转换
public static void main(String[] args) { final Object object = new Object(); Thread t1 = new Thread(new Runnable() { @Override public void run() { synchronized (object) { while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }, "t1"); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { synchronized (object) { System.out.println("hehe"); } } }, "t2"); t2.start(); }
使用 jconsole 可以看到 t1 的状态是 TIMED_WAITING , t2 的状态是 BLOCKED
将t1中的sleep换成wait
public static void main(String[] args) { final Object object = new Object(); Thread t1 = new Thread(new Runnable() { @Override public void run() { synchronized (object) { while (true) { try { // Thread.sleep(1000); object.wait(); .........
使用 jconsole 可以看到 t1 的状态是 WAITING
结论:
- BLOCKED 表示等待获取锁, WAITING 和 TIMED_WAITING 表示等待其他线程发来通知.
- TIMED_WAITING 线程在等待唤醒,但设置了时限; WAITING 线程在无限等待唤醒