方法一:继承Thread类
class MyThread extends Thread{
@Override
public void run() {
System.out.println("线程1");
}
}
public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();//start()方法启动线程
//和上面的方法一样,只不过使用匿名内部类实现
Thread thread1 = new Thread(){
@Override
public void run() {
System.out.println("线程2");
}
};
thread1.start();
}
}
方法二:实现Runnable接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程1");
}
}
public class Test {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
//匿名内部类实现
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程2");
}
});
thread2.start();
//lambda表达式实现
Thread thread3 = new Thread(() -> System.out.println("线程3"));
thread3.start();
}
}
方法 | 说明 |
Thread() | 创建线程对象 |
Thread(Runnable target) | 使用Runnable对象创建线程对象 |
Thread(String name) | 创建线程对象并命名 |
Thread(Runnable target,String name) | 使用Runnable对象创建线程对象,并命名 |
Thread(ThreadGroup group,Runnable target) | 线程可以被用来分组管理,分好的组即为线程组(了解即可) |
属性 | 获取方法 |
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否后台线程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
System.out.println("线程开始");
try {
Thread.sleep(1000);//休眠线程 xxx ms
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},"1号线程");
thread.setDaemon(true);//设置为后台线程
thread.start();
System.out.println(thread.getName() + " " + thread.isAlive());
Thread.sleep(3000);
System.out.println("线程结束");
System.out.println(thread.isAlive());
}
}
作用功能:
- start()方法内部是会调用系统的API,在系统内核创建一个线程
- run()方法只是描述线程具体实现的任务(会在start创建好之后会自动被调用)
运行结果:
- start调用方法后, start方法内部会调用Java 本地方法(封装了对系统底层的调用)真正的启动线程,并执行run方法中的代码,run 方法执行完成后线程进入销毁阶段。
- run方法是一个类中的普通方法,主动调用和调用普通方法一样,会顺序执行一次
在Java中,终止/销毁一个线程的做法比较单一,就是尽快让 run 方法执行结束。
方法一: 在代码中手动创建一个标志位,来作为 run 的执行结束条件,比如在很多线程中,执行时间长往往是写了一个循环。
public class Demo {
private static boolean isQuit = false;//通过类属性来控制
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
while (!isQuit){
System.out.println("666");
}
});
thread.start();
Thread.sleep(1);
isQuit = true;
}
}
注:这里的 isQuit 不能是局部变量,因为如果是局部变量就不满足 lambda表达式中的变量捕获语法。
但是上面的方法有两个缺点:1. 需要手动创建变量 2. 当线程内部在 sleep 的时候,主线程修改变量时,新线程内部不能及时响应,所以Java提供了另一种解决方法:
方法二:使用 interupt() 和 isInterrupted()
方法 | 说明 |
public void interrupt() | 中断对象关联的线程,如果线程阻塞,则以异常方式通知,否则设置标志位 |
public static boolean interrupted() | 判断当前线程中的标志位是否设置,调用后清除标志位 |
public boolean isInterrupted() | 判断对象关联的线程的标志位是否设置,调用后不清除标志 |
public class Demo {
public static void main(String[] args) {
Thread thread = new Thread(()->{
// Thread.currentThread()作用是得到当前的线程
// isInterrupted() 判断标识符是否为false
//或者 while(!Thread.interrupted()) 效果一样
while(!Thread.currentThread().isInterrupted()){
System.out.println("线程工作中!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();//打印异常
}
}
});
thread.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();//将标识符设置为true
}
}
但是报错后,该线程没有中断,而是继续执行,这是为什么呢?
这是因为当我们将 标识符设为true 时,正好线程在sleep,会触发sleep内部的一个异常,从而会将线程从sleep中唤醒,但是在sleep抛出异常的同时,它会自动删除刚才设置的 标志位,这将会使 interrupt 这一操作好像没有被执行。
为什么Java会这样设定呢? 因为 Java 是希望当 线程收到 "中断" 信号时,它能自由决定接下来要怎么处理,比如:我们可以在打印报错后 接着写一些代码 :
public class Demo {
public static void main(String[] args) {
Thread thread = new Thread(()->{
// Thread.currentThread()作用是得到当前的线程
// isInterrupted() 判断标识符是否为false
//或者 while(!Thread.interrupted()) 效果一样
while(!Thread.currentThread().isInterrupted()){
System.out.println("线程工作中!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();//打印异常
System.out.println("还需要完成的操作...");//2.
break;//1.直接退出
}
}
});
thread.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();//将标识符设置为true
}
}
注:
作用:让一个线程等待另一个线程执行结束后,在继续执行。本质上是控制线程结束的顺序。
方法 | 作用 |
public void join() | 等待线程结束 |
public void join(long millis) | 等待线程结束,但是最多等待 millis 毫秒 |
public void join(long millis, int nanos) | 同上,但是精度更高 |
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for (int i = 0; i < 5; i++) {
System.out.println("线程工作中!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
System.out.println("main线程开始等待");
thread.join();
System.out.println("等待结束");
}
}
注:
方法 | 作用 |
public static Thread currentThread() | 返回当前线程对象的引用 |
public static void sleep(long millis) throws interruptedException | 当前线程休眠millis毫秒 |
public static void sleep(long millis, int nanos) throws interruptedException | 同上,精度更高 |
public class Demo2 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
// getState() 获得当前线程的状态
System.out.println(thread.getState());
thread.start();
for (int i = 0; i < 3; i++) {
System.out.println(thread.getState());
Thread.sleep(200);
}
thread.join();
System.out.println(thread.getState());
}
}