一. 线程创建
Java 提供了两种以编程方式创建线程的方法。
- 实现 java.lang.Runnable 接口。
- 扩展 java.lang.Thread 类
Runnable接口
Runnable接口用来指定每个线程要执行的任务, 还需要通过Thread来调用开启线程.
class ThreadTest1 implements Runnable {
@Override
public void run() {
System.out.println("ThreadTest2.run");
}
}
public class Demo {
public static void main(String[] args) {
Thread t1 = new Thread(new ThreadTest1);
t1.start;
}
}
Thread类
继承Thread类, 然后创建这个类的实例, 继承该类必须重写run()方法
class ThreadTest2 extends Thread {
@Override
public void run() {
System.out.println("ThreadTest1.run");
}
}
public class Demo {
public static void main(String[] args) {
ThreadTest1 t2= new ThreadTest2();
t1.start();
}
}
Thread类常用构造方法
Thread()
- 创建线程对象
Thread(Runable target)
- 根据Runable对象创建线程
Thread(String name)
- 创建一个名为name的线程
Thread(Runable target, String name)
-根据Runable对象创建名为name的线程
Thread常用属性
属性 | 获取方法 |
---|---|
ID | getId() |
名称 | getName() |
状态 | getState() |
优先级 | getPriority() |
是否后台线程 | isDaemon() |
是否存活 | isAlive() |
是否被中断 | isInterrupted() |
由于Java不支持多继承, 所以更多的使用接口实现线程
当我们创建出线程之后, 并不代表线程就在运行了, 当调用start()
方法之后, 线程也开始执行
二. 线程中断
线程执行完之后会自动中断, 如果想让线程在执行过程中发生中断有两种方式
- 通过共享的标志位判断
- 通过
interrupt()
方法
第一种方式:
public class ThreadTest {
// 线程共享的标志位
public static boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread() {
@Override
public void run() {
while(!flag) {
System.out.println("t1.run");
try {
// t1线程休眠1000ms
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.start();
// main线程休眠5000ms
Thread.sleep(5000);
flag = true;
}
}
通过标志位的方式我们会发现, 当一个程序中出现多个线程需要中断, 不可能都用这一个标志位的方式,所以我们来看interrupt()
// 判断当前线程的中断标志位是否设置,调用后清除标志位
// 属于静态的 每个程序一个标志
public static boolean interrupted()
// 判断对象关联的线程的标志位是否设置,调用后不清除标志位
// 每个实例一个标志
public boolean isInterrupted()
public class ThreadTest06 {
public static void main(String[] args) {
Thread t1 = new Thread() {
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()) {
System.out.println("t1.run");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("结束!");
break;
}
}
}
};
t1.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.interrupt();
}
sleep()
- 它可以暂停线程的执行
- 线程在执行之前的睡眠时间取决于系统调度的时间, 当系统不忙时, 该时间接近于指定睡眠时间, 当系统忙时, 该时间大于指定睡眠时间.
- 线程睡眠不会丢失当前线程已获得的任何监视器或锁。
- 线程在睡眠时发生阻塞,等待会抛出InterruptedException
三. 线程等待
join()
在当前线程调用另一个线程的join()
方法, 会将当前线程挂起, 直到另一个线程结束.
public static void main(String[] args) throws InterruptedException {
// 通过Lambda表达式创建线程
Thread t1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("t1.run");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t1.join();
for (int i = 0; i < 5; i++) {
System.out.println("main.run");
Thread.sleep(200);
}
}
执行结果
t1.run
t1.run
t1.run
t1.run
t1.run
main.run
main.run
main.run
main.run
main.run
在mian线程调用t1线程的join方法, 只有当t1线程执行完毕才执行main线程
join()
方法会死等, 当调用的线程是一个死循环时, 就造成整个线程进入死循环. 可以加入等待时间
// 等待线程结束,最多等 millis 毫秒
public void join(long millis)
四. 获取线程实例
通过Thread.currentThread()
方法可以获得当前线程对象的引用
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
Thread thread = Thread.currentThread();
System.out.println(thread);
});
t1.start();
System.out.println(Thread.currentThread());
}
执行结果
Thread[main,5,main]
Thread[Thread-0,5,main]