多线程调用
Java 中 JVM 允许程序运行多个线程,使用 java.lang.Thread 类代表 线程,所有的线程对象都必须是 Thread类或子类的实例。
Thread
类的特点:
- 每个线程都必须重写Thread对象的
run()
方法来完成执行,因此run()
也叫做线程执行体; - 线程需要通过Thread对象的
start()
方法来启动该线程,而非直接调用run()
方法; - 想要实现多线程,必须在主线程(main方法)中创建新的线程对象,而非多次调用
start()
;
创建线程的方式
继承Thread类
Thread 类有四个构造器,后续都会讲到并使用:
构造器 | 作用 |
---|---|
public Thread() | 创建一个新的线程对象 |
public Thread(String name) | 创建一个指定名字的新的线程对象 |
public Thread(Runnable target) | 创建一个新的线程的目标对象,它实现了 Runnable 接口,并重写了 run 方法 |
public Thread(Runnable target, String name) | 创建一个新的线程的目标对象,并指定名字 |
通过继承Thread类来 创建 并 启动多线程:
java
class PrintfNumber extends Thread {
//通过构造函数为当前线程指定名称
public PrintfNumber(String name) {
super(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "hello");
}
}
java
public static void main(String[] args) {
PrintfNumber p1 = new PrintfNumber("Thread1");
p1.start();
}
其中 mian()
方法可以理解为主线程,而自定义的 PrintfNumber 就是一个分线程,运行在主线程中。
拓展写法
匿名线程 是一种特殊的线程创建方式,它不需要显式地定义一个线程类,而是直接在需要的地方创建一个线程对象。
java
//匿名线程
new Thread() {
@Override
public void run() {
System.out.println("Hello from anonymous thread!");
}
}.start();
//命名线程
new Thread("thread") {
@Override
public void run() {
System.out.println("Hello from anonymous thread!");
}
}.start();
实现Runnable接口
Java中有单继承的限制,第一种方式当我们继承了Thread类后,就无法继承其他类了。
Java核心类库中提供了 Runnable
接口,我们可以继承 Runnable
接口,规避上面无法继承其他类的情况。
java
class EvenNumberThread implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "hello");
}
}
java
public static void main(String[] args) {
EvenNumberThread e = new EvenNumberThread();
//这时需要通过 Thread() 进行调用, Thread()可以接受一个Runnable对象
new Thread(e).start();
}
拓展写法
java8 之后,新增了 lambda 语法糖写法:
java
//Thread()中传入一个 Runnable 对象
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello from anonymous thread!");
}
}).start();
//简化写法
new Thread(() -> System.out.println("Hello from anonymous thread!")
.start();
线程常用方法
方法 | 描述 |
---|---|
currentThread() | 获取当前执行代码的线程 |
getName() | 获取当前线程的名字 |
setName() | 设置当前线程的名字 |
sleep(1000) | 使线程睡眠指定的时长(单位:毫秒) |
yield() | 执行该方法,表示当前线程将释放CPU的执行权 |
join() | 子线程调用该方法,表示主线程会阻塞,直到子线程执行完成后,主线程再执行 |
isAlive() | 判断当前线程是否存活 |
java
public static void main(String[] args) {
EvenNumber e1 = new EvenNumber();
e1.start();
for (int i = 1; i <= 100; i++) {
if (i % 20 == 0) {
//主线程释放CPU执行权,让子线程优先执行
Thread.yield();
}
}
}
class EvenNumber extends Thread {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(i);
}
}
}
java
public static void main(String[] args) throws InterruptedException {
EvenNumber e2 = new EvenNumber();
e2.start();
for (int i = 1; i <= 100; i++) {
if (i % 20 == 0) {
//主线程将阻塞,把运行权给到分线程,当分线程执行完成后主线程再执行
e2.join();
}
}
}
class EvenNumber extends Thread {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(i);
}
}
}
线程优先级
每个线程都有一定的优先级,相同优先级的线程使用分时调度策略,优先级高的线程采用抢占式策略,获得较多的执行机会。
设置线程优先级方法:
方法 | 描述 |
---|---|
getPriority | 获取当前线程优先级 |
setPriority() | 设置当前线程优先级,取值范围 [1, 10] 之间 |
Java自带的线程优先级常量:
常量 | 描述 |
---|---|
MIN_PRIORITY | 最小线程级别,值为 1 |
NORM_PRIORITY | 默认线程级别,值为 5 |
MAX_PRIORITY | 最大线程级别,值为 10 |
java
public class PriorityTest {
public static void main(String[] args) {
EvenNumber e4 = new EvenNumber();
//为子线程设置最大线程级别
e4.setPriority(Thread.MAX_PRIORITY);
e4.start();
//为main主线程,设置最小线程级别
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getPriority() + ":" + i);
}
}
}
class EvenNumber extends Thread {
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getPriority() + ":" + i);
}
}
}