Java并发编程:从基础到高级应用

16.1 并发编程概述
16.1.1 学习目标与重点提示
学习目标:理解并发编程的基本概念,掌握线程的创建和使用方法,了解线程同步和通信的原理,学会使用并发工具类,掌握并发编程中的常见问题及解决方案。
重点:线程的创建与使用(继承Thread类、实现Runnable接口、使用Callable接口和FutureTask类)、线程同步(synchronized关键字、Lock接口)、线程通信(wait()、notify()、notifyAll()方法)、并发工具类(Executor、ExecutorService、Future、Callable、Semaphore、CountDownLatch)。
16.1.2 并发编程的基本概念
进程:进程是操作系统中的一个执行单元,是程序的一次执行过程。
线程:线程是进程中的一个执行单元,是程序执行的最小单位。
并发:并发是指多个线程同时执行,但在同一时刻只有一个线程在执行。
并行:并行是指多个线程同时执行,且在同一时刻有多个线程在执行。
16.2 线程的创建与使用
Java提供了三种创建线程的方法:继承Thread类、实现Runnable接口、使用Callable接口和FutureTask类。
16.2.1 继承Thread类
定义:继承Thread类是Java中最简单的创建线程的方法。
示例:
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程" + Thread.currentThread().getName() + "正在执行...");
}
}
public class TestThread {
public static void main(String[] args) {
// 创建MyThread对象
MyThread thread1 = new MyThread();
MyThread thread2 = new MyThread();
// 设置线程名
thread1.setName("线程1");
thread2.setName("线程2");
// 启动线程
thread1.start();
thread2.start();
// 输出主线程名
System.out.println("主线程" + Thread.currentThread().getName() + "正在执行...");
}
}
输出结果:
线程1正在执行...
主线程main正在执行...
线程2正在执行...
✅ 结论:继承Thread类是Java中最简单的创建线程的方法,但由于Java是单继承的,这种方法有一定的局限性。
16.2.2 实现Runnable接口
定义:实现Runnable接口是Java中最常用的创建线程的方法。
示例:
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程" + Thread.currentThread().getName() + "正在执行...");
}
}
public class TestRunnable {
public static void main(String[] args) {
// 创建MyRunnable对象
MyRunnable runnable = new MyRunnable();
// 创建Thread对象
Thread thread1 = new Thread(runnable, "线程1");
Thread thread2 = new Thread(runnable, "线程2");
// 启动线程
thread1.start();
thread2.start();
// 输出主线程名
System.out.println("主线程" + Thread.currentThread().getName() + "正在执行...");
}
}
输出结果:
线程1正在执行...
主线程main正在执行...
线程2正在执行...
✅ 结论:实现Runnable接口是Java中最常用的创建线程的方法,由于Java是多实现的,这种方法没有局限性。
16.2.3 使用Callable接口和FutureTask类
定义:使用Callable接口和FutureTask类是Java中最灵活的创建线程的方法。
示例:
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("线程" + Thread.currentThread().getName() + "正在执行...");
return 100;
}
}
public class TestCallable {
public static void main(String[] args) {
// 创建MyCallable对象
MyCallable callable = new MyCallable();
// 创建FutureTask对象
FutureTask<Integer> futureTask = new FutureTask<>(callable);
// 创建Thread对象
Thread thread = new Thread(futureTask, "线程1");
// 启动线程
thread.start();
try {
// 获取线程返回值
Integer result = futureTask.get();
System.out.println("线程返回值:" + result);
} catch (Exception e) {
e.printStackTrace();
}
// 输出主线程名
System.out.println("主线程" + Thread.currentThread().getName() + "正在执行...");
}
}
输出结果:
线程1正在执行...
线程返回值:100
主线程main正在执行...
✅ 结论:使用Callable接口和FutureTask类是Java中最灵活的创建线程的方法,这种方法可以获取线程的返回值。
16.3 线程同步
线程同步是指多个线程同时访问共享资源时,保证资源的一致性和完整性。Java提供了两种线程同步的方法:synchronized关键字和Lock接口。
16.3.1 synchronized关键字
定义:synchronized关键字是Java中最常用的线程同步方法。
示例:
class Counter {
private int count;
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public synchronized int getCount() {
return count;
}
}
class MyRunnable implements Runnable {
private Counter counter;
public MyRunnable(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
}
}
public class TestSynchronized {
public static void main(String[] args) {
// 创建Counter对象
Counter counter = new Counter();
// 创建MyRunnable对象
MyRunnable runnable = new MyRunnable(counter);
// 创建Thread对象
Thread thread1 = new Thread(runnable, "线程1");
Thread thread2 = new Thread(runnable, "线程2");
// 启动线程
thread1.start();
thread2.start();
try {
// 等待线程结束
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出count的值
System.out.println("count的值:" + counter.getCount());
}
}
输出结果:
count的值:2000
✅ 结论:synchronized关键字是Java中最常用的线程同步方法,这种方法可以保证资源的一致性和完整性。
16.3.2 Lock接口
定义:Lock接口是Java中最灵活的线程同步方法。
示例:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class Counter {
private int count;
private Lock lock = new ReentrantLock();
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
public void decrement() {
lock.lock();
try {
count--;
} finally {
lock.unlock();
}
}
public int getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
}
class MyRunnable implements Runnable {
private Counter counter;
public MyRunnable(Counter counter) {
this.counter = counter;
}
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
counter.increment();
}
}
}
public class TestLock {
public static void main(String[] args) {
// 创建Counter对象
Counter counter = new Counter();
// 创建MyRunnable对象
MyRunnable runnable = new MyRunnable(counter);
// 创建Thread对象
Thread thread1 = new Thread(runnable, "线程1");
Thread thread2 = new Thread(runnable, "线程2");
// 启动线程
thread1.start();
thread2.start();
try {
// 等待线程结束
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 输出count的值
System.out.println("count的值:" + counter.getCount());
}
}
输出结果:
count的值:2000
✅ 结论:Lock接口是Java中最灵活的线程同步方法,这种方法可以保证资源的一致性和完整性。
16.4 线程通信
线程通信是指多个线程之间进行信息交换的过程。Java提供了三种线程通信的方法:wait()、notify()、notifyAll()方法。
16.4.1 wait()、notify()、notifyAll()方法
定义:wait()、notify()、notifyAll()方法是Java中最常用的线程通信方法。
示例:
class Message {
private String content;
private boolean flag = false;
public synchronized void write(String content) {
while (flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.content = content;
flag = true;
notifyAll();
}
public synchronized String read() {
while (!flag) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
flag = false;
notifyAll();
return content;
}
}
class Writer implements Runnable {
private Message message;
public Writer(Message message) {
this.message = message;
}
@Override
public void run() {
String[] messages = {"Hello", "World", "Java"};
for (String content : messages) {
message.write(content);
System.out.println("写入消息:" + content);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Reader implements Runnable {
private Message message;
public Reader(Message message) {
this.message = message;
}
@Override
public void run() {
for (int i = 0; i < 3; i++) {
String content = message.read();
System.out.println("读取消息:" + content);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class TestThreadCommunication {
public static void main(String[] args) {
// 创建Message对象
Message message = new Message();
// 创建Writer和Reader对象
Writer writer = new Writer(message);
Reader reader = new Reader(message);
// 创建Thread对象
Thread thread1 = new Thread(writer, "写入线程");
Thread thread2 = new Thread(reader, "读取线程");
// 启动线程
thread1.start();
thread2.start();
}
}
输出结果:
写入消息:Hello
读取消息:Hello
写入消息:World
读取消息:World
写入消息:Java
读取消息:Java
✅ 结论:wait()、notify()、notifyAll()方法是Java中最常用的线程通信方法,这种方法可以实现多个线程之间的信息交换。
16.5 并发工具类
Java提供了丰富的并发工具类,用于简化并发编程。
16.5.1 Executor、ExecutorService、Future、Callable
定义:Executor、ExecutorService、Future、Callable是Java中最常用的并发工具类。
示例:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("线程" + Thread.currentThread().getName() + "正在执行...");
return 100;
}
}
public class TestExecutor {
public static void main(String[] args) {
// 创建ExecutorService对象
ExecutorService executorService = Executors.newFixedThreadPool(2);
// 创建MyCallable对象
MyCallable callable = new MyCallable();
// 提交任务
Future<Integer> future1 = executorService.submit(callable);
Future<Integer> future2 = executorService.submit(callable);
try {
// 获取任务返回值
Integer result1 = future1.get();
Integer result2 = future2.get();
System.out.println("任务1返回值:" + result1);
System.out.println("任务2返回值:" + result2);
} catch (Exception e) {
e.printStackTrace();
}
// 关闭ExecutorService
executorService.shutdown();
}
}
输出结果:
线程pool-1-thread-1正在执行...
线程pool-1-thread-2正在执行...
任务1返回值:100
任务2返回值:100
✅ 结论:Executor、ExecutorService、Future、Callable是Java中最常用的并发工具类,这种方法可以简化并发编程。
16.5.2 Semaphore
定义:Semaphore是Java中最常用的并发工具类之一,用于控制同时访问共享资源的线程数。
示例:
import java.util.concurrent.Semaphore;
class MyRunnable implements Runnable {
private Semaphore semaphore;
public MyRunnable(Semaphore semaphore) {
this.semaphore = semaphore;
}
@Override
public void run() {
try {
// 获取许可
semaphore.acquire();
System.out.println("线程" + Thread.currentThread().getName() + "正在执行...");
// 模拟线程执行时间
Thread.sleep(1000);
System.out.println("线程" + Thread.currentThread().getName() + "执行完毕...");
// 释放许可
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TestSemaphore {
public static void main(String[] args) {
// 创建Semaphore对象
Semaphore semaphore = new Semaphore(2);
// 创建MyRunnable对象
MyRunnable runnable = new MyRunnable(semaphore);
// 创建Thread对象
Thread thread1 = new Thread(runnable, "线程1");
Thread thread2 = new Thread(runnable, "线程2");
Thread thread3 = new Thread(runnable, "线程3");
// 启动线程
thread1.start();
thread2.start();
thread3.start();
}
}
输出结果:
线程1正在执行...
线程2正在执行...
线程1执行完毕...
线程2执行完毕...
线程3正在执行...
线程3执行完毕...
✅ 结论:Semaphore是Java中最常用的并发工具类之一,这种方法可以控制同时访问共享资源的线程数。
16.5.3 CountDownLatch
定义:CountDownLatch是Java中最常用的并发工具类之一,用于等待多个线程完成后再执行后续操作。
示例:
import java.util.concurrent.CountDownLatch;
class MyRunnable implements Runnable {
private CountDownLatch countDownLatch;
public MyRunnable(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
try {
System.out.println("线程" + Thread.currentThread().getName() + "正在执行...");
// 模拟线程执行时间
Thread.sleep(1000);
System.out.println("线程" + Thread.currentThread().getName() + "执行完毕...");
// 计数减1
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TestCountDownLatch {
public static void main(String[] args) {
// 创建CountDownLatch对象
CountDownLatch countDownLatch = new CountDownLatch(2);
// 创建MyRunnable对象
MyRunnable runnable = new MyRunnable(countDownLatch);
// 创建Thread对象
Thread thread1 = new Thread(runnable, "线程1");
Thread thread2 = new Thread(runnable, "线程2");
// 启动线程
thread1.start();
thread2.start();
try {
// 等待计数减到0
countDownLatch.await();
System.out.println("所有线程执行完毕...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出结果:
线程1正在执行...
线程2正在执行...
线程1执行完毕...
线程2执行完毕...
所有线程执行完毕...
✅ 结论:CountDownLatch是Java中最常用的并发工具类之一,这种方法可以等待多个线程完成后再执行后续操作。
总结
本章我们学习了Java的并发编程,包括线程的创建与使用、线程同步、线程通信、并发工具类等内容。其中,线程的创建与使用(继承Thread类、实现Runnable接口、使用Callable接口和FutureTask类)、线程同步(synchronized关键字、Lock接口)、线程通信(wait()、notify()、notifyAll()方法)、并发工具类(Executor、ExecutorService、Future、Callable、Semaphore、CountDownLatch)是本章的重点内容。从下一章开始,我们将学习Java的Web开发、Spring框架等内容。
1万+

被折叠的 条评论
为什么被折叠?



