Java线程一共6个状态。
package chapter09;
public class Java01_Thread {
public static void main(String[] args) {
// TODO 线程
// Thread是线程类
// currentThread 方法用于获取当前正在运行的线程
// getName 方法获取线程的名字
// main方法运行在main线程中
// System.out.println(Thread.currentThread().getName());
//
// // todo 创建线程
Thread t = new Thread();
// MyThread t = new MyThread();
// // todo 启动线程
// t.start();
//
// System.out.println(Thread.currentThread().getName());
// todo 构建线程对象时,可以只把逻辑传递给这个对象
// 传递逻辑时,需要遵循规则: () -> { 逻辑 }
// ()->{} 是一个 lambda 表达式。它实现了 Runnable 接口的 run 方法
// Runnable 接口是一个函数式接口(只有一个抽象方法的接口),因此可以使用 lambda 表达式来简化代码。
// Lambda 表达式 简化了函数式接口的实现,使代码更简洁。
// 等价写法 可以使用匿名内部类来实现
Thread thread1 = new Thread(() -> {
System.out.println("线程执行1");
});
// 等价于下面的写法
// 构建线程对象时,可以传递实现了Runnable接口的对象,一般使用匿名类
// Thread thread1 = new Thread(new Runnable() {
// @Override
// public void run() {
// System.out.println("线程执行1");
// }
//});
thread1.start();
}
}
// TODO 声明自定义线程类
class MyThread extends Thread {
@Override
public void run() {
System.out.println("MyThread :" + Thread.currentThread().getName());
}
}
package chapter09;
import java.io.IOException;
public class Java02_多线程 {
public static void main(String[] args) throws InterruptedException {
// TODO 多线程 - 执行方式 (串行,并发)
// 并发执行:多个线程是独立的,谁抢到CPU执行权,谁就能执行
// int i = 0;
// while (i++ < 100) {
// MyThread1 t1 = new MyThread1();
// MyThread2 t2 = new MyThread2();
// t1.start();
// t2.start();
// System.out.println("xxxxxxxxxxxx\n");
// }
// 串行执行:多个线程连接成串,然后按照顺序执行
int i = 0;
while (i++ < 100) {
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
t1.start();
t2.start();
// 将线程连接成串
t1.join();
t2.join();
System.out.println("xxxxxxxxxxxx\n");
}
}
}
class MyThread1 extends Thread {
@Override
public void run() {
System.out.println("MyThread1 :" + Thread.currentThread().getName());
}
}
class MyThread2 extends Thread {
@Override
public void run() {
System.out.println("MyThread2 :" + Thread.currentThread().getName());
try {
Thread.sleep(1000); // 休眠1秒钟
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
四种常见的线程池
package chapter09;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Java05_Thread_Pool {
public static void main(String[] args) {
// TODO 线程 - 线程池
// 所谓线程池,其实就是线程对象的容器
// 可以根据需要,在启动时,创建一个或多个线程对象
// Java中有4种比较常见的线程池
// 1. 创建固定数量的线程对象
// ExecutorService是线程服务对象
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 2. 根据需求动态创建线程, 创建的线程可以重复使用,只是当目前线程不够了他会动态增加线程
executorService = Executors.newCachedThreadPool();
// 3. 单一线程
executorService = Executors.newSingleThreadExecutor();
// 4. 定时调度线程, 线程有3个,但是线程在什么时候执行我们可以去定义他
executorService = Executors.newScheduledThreadPool(3);
for (int i = 0; i < 5; i++) {
executorService.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
}
}
在 Java 中,创建并启动一个新的线程通常有两种主要的方式:继承 Thread 类和实现 Runnable 接口。
- 通过继承 Thread 类来创建一个新的线程类,并重写 Thread 类的 run() 方法。
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is running");
}
public static void main(String[] args) {
MyThread t = new MyThread();
t.start(); //启动线程
}
}
- 通过实现 Runnable 接口并实现其 run() 方法,然后将 Runnable 实例传递给 Thread 对象。
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Thread is running");
}
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
}
}
特性 | 继承 Thread 类 | 实现 Runnable 接口 |
---|---|---|
继承 | 不支持多继承,限制较大 | 支持多继承,更灵活 |
代码解耦 | 线程逻辑和线程控制耦合 | 线程逻辑和线程控制分离 |
复用性 | 不易复用 | 更易复用 |
共享资源 | 需要额外处理 | 自然适应共享资源 |
ps:若两个同时使用呢?
class BothRunnableThread {
public static void main(String[] args) {
// 创建一个匿名内部类实现 Runnable 接口的 run 方法
new Thread(new Runnable() {
@Override
public void run() {
// 这个 run 方法来自于 Runnable 接口
System.out.println("I am runnable");
}
}) {
// 创建一个匿名内部类继承 Thread 类并重写其 run 方法
@Override
public void run() {
// 这个 run 方法来自于 Thread 类
System.out.println("I am thread");
}
}.start(); // 启动线程
}
}
结果是:
原因:
创建了一个实现了 Runnable 接口的匿名内部类的对象,然后这个Runnable类的匿名内部类的对象被传给Thread的target。
但是Thread的下面三行run方法被重写了,也就不用管Runnable类的target了,虽然Runnable类的target的run方法被重写了,所以没机会执行Runnable类的target的run方法了。