目录
一、Thread类的介绍
1、定义
2、构造方法
3、常见属性
二、线程创建
1、继承Thread类
2、实现Runnable接口
3、匿名内部类
(1)、匿名内部类创建Thread子类对象
(2)、匿名内部类创建Runnable子类对象
4、使用lambda表达式
注:
三、线程中断
1、手动设置标志位
2、调用 interrupt() 方法
四、线程等待
五、线程休眠
六、获取当前线程实例
Thread类是JVM 用来管理线程的一个类,每个线程都有一个唯一的 Thread 对象与之关联。每个执行流,都需要有一个对象来描述,而 Thread 类的对象就是用来描述线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。
方法 | 说明 | 举例 |
Thread() | 创建线程对象 | Thread t1 = new Thread(); |
Thread(Runnable target) | 使用Runnable对象创建线程对象 | Thread t2 = new Thread(new MyRunnable()); |
Thread(String name) | 创建线程对象,并命名 | Thread t3 = new Thread("线程1"); |
Thread(Runnable target,String name) | 使用Runnable对象创建线程对象,并命名 | Thread t4 = new Thread(new MyRunnable(), "线程2"); |
Thread(ThreadGroup group,Runnable target) | 线程可以被用来分组管理,分好的组即为线程组 | \ |
属性 | 获取方法 | 说明 |
ID | getId() | ID 是线程的唯一标识,不同线程不会重复 |
名称 | getName() | 名称是各种调试工具用到的 |
状态 | getState() | 状态表示线程当前所处的一个情况 |
优先级 | getPriority() | 优先级高的线程理论上来说更容易被调度到 |
是否后台线程 | isDaemon() | JVM会在一个进程的所有非后台线程结束后才会结束运行。 |
是否存活 | isAlive() | run 方法是否运行结束。 |
是否中断 | isInterrupted() | \ |
class MyThread extends Thread{@Overridepublic void run(){while (true){System.out.println("线程1");}}
}
public class Demo01 {public static void main(String[] args) {MyThread t=new MyThread();t.start();}
}
class MyRunnable implements Runnable{@Overridepublic void run(){while (true){System.out.println("线程2");}}
}
public class Demo02 {public static void main(String[] args) {MyRunnable runnable=new MyRunnable();Thread t=new Thread(runnable);t.start();}
}
注:相比于继承 Thread 类,可以直接使用 this 表示当前线程对象的引用。实现 Runnable 接口,this 表示的是 MyRunnable 的引用,需要使用 Thread.currentThread()。
public class Demo03 {public static void main(String[] args) {Thread t=new Thread(){@Overridepublic void run(){while (true){System.out.println("线程3");}};t.start();while (true){System.out.println("main方法");}}
}
public class demo04 {public static void main(String[] args) {Thread t=new Thread(new Runnable() {@Overridepublic void run() {while (true){System.out.println("线程4");}}});t.start();while (true){System.out.println("main方法");}}
}
public class Demo05 {public static void main(String[] args) {Thread t=new Thread(()->{while (true){System.out.println("线程5");}});t.start();while (true){System.out.println("main方法");}}
}
上面我们通过覆写 run 方法创建一个线程对象,但线程对象被创建出来并不意味着线程就开始运行了。覆写 run 方法是提供给线程要做的事情的指令清单,run不会创建新的线程,其是在main线程中执行的。调用 start 方法, 才真的在操作系统的底层创建出一个线程。
使用自定义的变量来作为标志位。
public class demo01 {public static boolean isQuit=false;public static void main(String[] args) {Thread t=new Thread(()->{while (!isQuit){System.out.println("hello 线程1");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("线程1终止");});t.start();try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}//修改isQuit=true;}
}
注:当把isQuit从成员变量改成局部变量时无法正常发挥作用。Java要求变量捕获,捕获的变量必须是final或“实际final”。
Thread内部包含一个boolean类型的变量作为线程是否被中断的标记。
可以使用Thread.interrupted()或Thread.currentThread().isInterrupted()代替自定义标志位。
方法 | 说明 |
public void interrupt() | 中断对象关联的线程,如果线程正在阻塞,则以异常方式通知, 否则设置标志位 |
public static boolean interrupted() | 判断当前线程的中断标志位是否设置,调用后清除标志位 |
public boolean isInterrupted() | 判断对象关联的线程的标志位是否设置,调用后不清除标志位 |
public class demo02 {public static void main(String[] args) {Thread t=new Thread(()->{//currentThread是获取到当前线程实例(t)//isInterrupted是t对象里自带的一个标志位while (!Thread.currentThread().isInterrupted()){System.out.println("hello 线程2");try {Thread.sleep(1000);} catch (InterruptedException e) {try {Thread.sleep(2000);} catch (InterruptedException ex) {throw new RuntimeException(ex);}break;}}});t.start();try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}//将t内部的标志设置成truet.interrupt();}
}
interrupt()方法的作用:
线程之间是并发执行的,操作系统对于线程的调度是无序的,无法判断两个线程的执行先后顺序。有些时候,我们需要能控制线程之间的顺序,线程等待就是其中一种控制线程执行顺序的手段,此处的等待主要是控制线程结束的先后顺序。
方法 | 说明 |
public void join() | 等待线程结束 |
public void join(long millis) | 等待线程结束,最多等 millis 毫秒 |
public void join(long millis, int nanos) | 同理,但可以更高精度 |
public class demo03 {public static void main(String[] args) throws InterruptedException {Thread t=new Thread(()->{System.out.println("hello 线程3");});t.start();//在main方法中等待t执行完后再执行main方法t.join();System.out.println("hello main");}
}
上图中我们通过在main方法中调用join()方法让main线程阻塞从而使“线程3”先执行,直到“线程3”执行完毕后main线程才从阻塞中解除继续执行。因此想让哪个线程阻塞,就要在哪个线程里调用join()方法。但当main线程调用join()方法时“线程3”已经结束,此时不再阻塞会立即往下执行。
join()方法分类:
当代码中的某个线程调用sleep()方法时,这个线程就从就绪队列移至阻塞队列暂时不参与调度等待sleep()时间结束,而当到达sleep()的时间则又会被调度到就绪队列。
方法 | 说明 |
public static void sleep(long millis) throws InterruptedException | 休眠当前线程 millis毫秒 |
public static void sleep(long millis, int nanos) throws InterruptedException | 可以更高精度的休眠 |
public class Demo06 {public static void main(String[] args){Thread t=new Thread(()->{while (true){System.out.println("线程6");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();}
}
注:因为线程的调度是不可控的,所以sleep()方法只能保证实际休眠时间大于等于参数设置的休眠时间的。
可以通过Thread.currentThread()的方式来调用,返回的是线程对象的引用,有时候也可以用this替代。
下一篇:特朗普移民政策动摇美国农业