Java多线程从基础到高级应用示例小结
作者:星河耀银海
Java多线程:从基础到高级应用

11.1 多线程概述
11.1.1 学习目标与重点提示
学习目标:理解多线程的基本概念,掌握线程的创建与管理方法,了解线程同步与通信的实现方式,掌握线程池的使用方法。
重点:线程的创建方式(继承Thread类、实现Runnable接口、使用Callable和Future)、线程同步(synchronized、Lock)、线程通信(wait/notify、await/signal)、线程池(Executor、ThreadPoolExecutor)。
11.1.2 多线程的基本概念
进程:一个正在运行的程序,包含代码、数据和资源。
线程:进程内部的一个执行单元,共享进程的资源。
多线程:一个进程包含多个线程,同时执行多个任务。
多线程的优势:
- 提高程序的执行效率。
- 充分利用CPU资源。
- 提高程序的响应速度。
多线程的劣势:
- 增加了程序的复杂度。
- 容易出现线程安全问题。
11.2 线程的创建与管理
Java中创建线程的方式有三种:继承Thread类、实现Runnable接口、使用Callable和Future。
11.2.1 继承Thread类
定义:继承Thread类,重写run()方法,创建Thread子类的对象,调用start()方法启动线程。
示例:
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
public class TestThread {
public static void main(String[] args) {
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
thread1.start();
thread2.start();
}
}输出结果:
Thread-0: 0
Thread-0: 1
Thread-1: 0
Thread-1: 1
Thread-0: 2
Thread-0: 3
Thread-1: 2
Thread-0: 4
Thread-1: 3
Thread-0: 5
Thread-0: 6
Thread-1: 4
Thread-0: 7
Thread-1: 5
Thread-0: 8
Thread-0: 9
Thread-1: 6
Thread-1: 7
Thread-1: 8
Thread-1: 9
✅ 结论:继承Thread类的方式简单,但Java不支持多继承,因此这种方式有局限性。
11.2.2 实现Runnable接口
定义:实现Runnable接口,重写run()方法,创建Runnable接口的实现类的对象,将该对象作为参数传递给Thread类的构造方法,调用start()方法启动线程。
示例:
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
public class TestRunnable {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread thread1 = new Thread(runnable);
Thread thread2 = new Thread(runnable);
thread1.start();
thread2.start();
}
}输出结果:
Thread-0: 0
Thread-0: 1
Thread-1: 0
Thread-1: 1
Thread-0: 2
Thread-0: 3
Thread-1: 2
Thread-0: 4
Thread-1: 3
Thread-0: 5
Thread-0: 6
Thread-1: 4
Thread-0: 7
Thread-1: 5
Thread-0: 8
Thread-0: 9
Thread-1: 6
Thread-1: 7
Thread-1: 8
Thread-1: 9
✅ 结论:实现Runnable接口的方式避免了Java不支持多继承的限制,但无法返回线程执行结果。
11.2.3 使用Callable和Future
定义:实现Callable接口,重写call()方法,创建Callable接口的实现类的对象,将该对象作为参数传递给FutureTask类的构造方法,将FutureTask类的对象作为参数传递给Thread类的构造方法,调用start()方法启动线程,通过FutureTask类的get()方法获取线程执行结果。
示例:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
return sum;
}
}
public class TestCallable {
public static void main(String[] args) {
MyCallable callable = new MyCallable();
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
try {
int result = futureTask.get();
System.out.println("1到100的和:" + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}输出结果:
1到100的和:5050
✅ 结论:使用Callable和Future的方式可以返回线程执行结果,但需要使用FutureTask类。
11.3 线程同步
线程同步是指多个线程同时访问共享资源时,保证资源的一致性和正确性。
11.3.1 synchronized关键字
定义:synchronized关键字用于实现线程同步,分为同步方法和同步块。
示例:
class Count {
private int count = 0;
public synchronized void increment() {
count++;
System.out.println(Thread.currentThread().getName() + ": " + count);
}
}
class MyThread extends Thread {
private Count count;
public MyThread(Count count) {
this.count = count;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
count.increment();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TestSynchronized {
public static void main(String[] args) {
Count count = new Count();
MyThread thread1 = new MyThread(count);
MyThread thread2 = new MyThread(count);
thread1.start();
thread2.start();
}
}输出结果:
Thread-0: 1
Thread-1: 2
Thread-0: 3
Thread-1: 4
Thread-0: 5
Thread-1: 6
Thread-0: 7
Thread-1: 8
Thread-0: 9
Thread-1: 10
Thread-0: 11
Thread-1: 12
Thread-0: 13
Thread-1: 14
Thread-0: 15
Thread-1: 16
Thread-0: 17
Thread-1: 18
Thread-0: 19
Thread-1: 20
✅ 结论:synchronized关键字可以保证线程同步,但性能较低。
11.3.2 Lock接口
定义:Lock接口用于实现线程同步,提供了更灵活的同步方式,如可重入锁、读写锁等。
示例:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Count {
private int count = 0;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
System.out.println(Thread.currentThread().getName() + ": " + count);
} finally {
lock.unlock();
}
}
}
class MyThread extends Thread {
private Count count;
public MyThread(Count count) {
this.count = count;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
count.increment();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TestLock {
public static void main(String[] args) {
Count count = new Count();
MyThread thread1 = new MyThread(count);
MyThread thread2 = new MyThread(count);
thread1.start();
thread2.start();
}
}输出结果:
Thread-0: 1
Thread-1: 2
Thread-0: 3
Thread-1: 4
Thread-0: 5
Thread-1: 6
Thread-0: 7
Thread-1: 8
Thread-0: 9
Thread-1: 10
Thread-0: 11
Thread-1: 12
Thread-0: 13
Thread-1: 14
Thread-0: 15
Thread-1: 16
Thread-0: 17
Thread-1: 18
Thread-0: 19
Thread-1: 20
✅ 结论:Lock接口可以提供更灵活的同步方式,但需要手动释放锁。
11.4 线程通信
线程通信是指多个线程之间的协作,如生产者-消费者模型。
11.4.1 wait/notify方法
定义:wait/notify方法用于实现线程通信,wait()方法使线程进入等待状态,notify()方法唤醒等待的线程。
示例:
class Warehouse {
private int count = 0;
private final int MAX_COUNT = 10;
public synchronized void produce() throws InterruptedException {
while (count == MAX_COUNT) {
wait();
}
count++;
System.out.println(Thread.currentThread().getName() + ": 生产了一个产品,当前产品数量:" + count);
notifyAll();
}
public synchronized void consume() throws InterruptedException {
while (count == 0) {
wait();
}
count--;
System.out.println(Thread.currentThread().getName() + ": 消费了一个产品,当前产品数量:" + count);
notifyAll();
}
}
class Producer extends Thread {
private Warehouse warehouse;
public Producer(Warehouse warehouse) {
this.warehouse = warehouse;
}
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
warehouse.produce();
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Consumer extends Thread {
private Warehouse warehouse;
public Consumer(Warehouse warehouse) {
this.warehouse = warehouse;
}
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
warehouse.consume();
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TestWaitNotify {
public static void main(String[] args) {
Warehouse warehouse = new Warehouse();
Producer producer1 = new Producer(warehouse);
Producer producer2 = new Producer(warehouse);
Consumer consumer1 = new Consumer(warehouse);
Consumer consumer2 = new Consumer(warehouse);
producer1.start();
producer2.start();
consumer1.start();
consumer2.start();
}
}输出结果:
Thread-0: 生产了一个产品,当前产品数量:1
Thread-1: 生产了一个产品,当前产品数量:2
Thread-2: 消费了一个产品,当前产品数量:1
Thread-3: 消费了一个产品,当前产品数量:0
Thread-0: 生产了一个产品,当前产品数量:1
Thread-1: 生产了一个产品,当前产品数量:2
Thread-2: 消费了一个产品,当前产品数量:1
Thread-3: 消费了一个产品,当前产品数量:0
...
✅ 结论:wait/notify方法可以实现线程通信,但需要在同步块中使用。
11.4.2 await/signal方法
定义:await/signal方法用于实现线程通信,await()方法使线程进入等待状态,signal()方法唤醒等待的线程。
示例:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Warehouse {
private int count = 0;
private final int MAX_COUNT = 10;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void produce() throws InterruptedException {
lock.lock();
try {
while (count == MAX_COUNT) {
condition.await();
}
count++;
System.out.println(Thread.currentThread().getName() + ": 生产了一个产品,当前产品数量:" + count);
condition.signalAll();
} finally {
lock.unlock();
}
}
public void consume() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
condition.await();
}
count--;
System.out.println(Thread.currentThread().getName() + ": 消费了一个产品,当前产品数量:" + count);
condition.signalAll();
} finally {
lock.unlock();
}
}
}
class Producer extends Thread {
private Warehouse warehouse;
public Producer(Warehouse warehouse) {
this.warehouse = warehouse;
}
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
warehouse.produce();
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Consumer extends Thread {
private Warehouse warehouse;
public Consumer(Warehouse warehouse) {
this.warehouse = warehouse;
}
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
warehouse.consume();
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TestAwaitSignal {
public static void main(String[] args) {
Warehouse warehouse = new Warehouse();
Producer producer1 = new Producer(warehouse);
Producer producer2 = new Producer(warehouse);
Consumer consumer1 = new Consumer(warehouse);
Consumer consumer2 = new Consumer(warehouse);
producer1.start();
producer2.start();
consumer1.start();
consumer2.start();
}
}输出结果:
Thread-0: 生产了一个产品,当前产品数量:1
Thread-1: 生产了一个产品,当前产品数量:2
Thread-2: 消费了一个产品,当前产品数量:1
Thread-3: 消费了一个产品,当前产品数量:0
Thread-0: 生产了一个产品,当前产品数量:1
Thread-1: 生产了一个产品,当前产品数量:2
Thread-2: 消费了一个产品,当前产品数量:1
Thread-3: 消费了一个产品,当前产品数量:0
...
✅ 结论:await/signal方法可以提供更灵活的线程通信方式,但需要使用Lock接口。
11.5 线程池
线程池是一种管理线程的方式,用于减少线程的创建和销毁开销。
11.5.1 Executor框架
定义:Executor框架是Java提供的线程池管理框架,包括Executor、ExecutorService、ThreadPoolExecutor等类。
示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class MyRunnable implements Runnable {
private int taskId;
public MyRunnable(int taskId) {
this.taskId = taskId;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ": 执行任务" + taskId);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ": 任务" + taskId + "完成");
}
}
public class TestExecutor {
public static void main(String[] args) {
// 创建线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
// 提交任务
for (int i = 0; i < 10; i++) {
executorService.submit(new MyRunnable(i));
}
// 关闭线程池
executorService.shutdown();
}
}输出结果:
pool-1-thread-1: 执行任务0
pool-1-thread-2: 执行任务1
pool-1-thread-3: 执行任务2
pool-1-thread-1: 任务0完成
pool-1-thread-1: 执行任务3
pool-1-thread-2: 任务1完成
pool-1-thread-2: 执行任务4
pool-1-thread-3: 任务2完成
pool-1-thread-3: 执行任务5
pool-1-thread-1: 任务3完成
pool-1-thread-1: 执行任务6
pool-1-thread-2: 任务4完成
pool-1-thread-2: 执行任务7
pool-1-thread-3: 任务5完成
pool-1-thread-3: 执行任务8
pool-1-thread-1: 任务6完成
pool-1-thread-1: 执行任务9
pool-1-thread-2: 任务7完成
pool-1-thread-3: 任务8完成
pool-1-thread-1: 任务9完成
✅ 结论:Executor框架可以方便地管理线程池,但需要根据实际需求选择合适的线程池类型。
总结
本章我们学习了Java的多线程,包括线程的创建与管理、线程同步、线程通信、线程池等内容。其中,线程的创建方式(继承Thread类、实现Runnable接口、使用Callable和Future)、线程同步(synchronized、Lock)、线程通信(wait/notify、await/signal)、线程池(Executor、ThreadPoolExecutor)是本章的重点内容。从下一章开始,我们将学习Java的网络编程、数据库编程等内容。
到此这篇关于Java多线程从基础到高级应用示例小结的文章就介绍到这了,更多相关java多线程应用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
