《Java编程中第17章的并发基础探究》
引言
在当下的软件开发领域,并发编程已然成为一项不可或缺的技能。随着多核处理器的广泛应用,充分利用系统资源、提升程序运行效率变得愈发关键。Java为开发者提供了强大的并发编程支持,使得编写高效的多线程程序成为可能。本章将会详尽阐释Java并发编程的基础内容,涵盖线程的创建、状态把控、同步机制以及常用的并发工具类等方面。
17.1 Java多线程概览
多线程指的是在一个程序里同时运行多个独立的执行流程(线程),每个线程能够执行不同的任务。与单线程相比,多线程具备如下优势:
- 提升程序的响应速度
- 充分利用多核处理器的资源
- 便于开展异步操作
在Java中,线程是程序执行的最小单元,一个进程能够包含多个线程,这些线程共享进程的资源,但各自拥有独立的执行栈和程序计数器。
多线程的应用场景:
- 图形界面应用程序(将UI线程与后台处理线程分离)
- 服务器程序(同时处理多个客户端请求)
- 数据处理(并行处理大量数据)
- 异步任务(例如文件下载、数据加载等)
17.2 创建任务与线程
在Java中,创建线程主要有两种途径:实现Runnable
接口和继承Thread
类。
17.2.1 实现Runnable接口
Runnable
接口仅有一个run()
方法,用于定义线程要执行的任务。实现Runnable
接口后,需将其实例传递给Thread
类的构造方法,而后调用start()
方法启动线程。
/**
* 借助Runnable接口创建线程的示例
*/
public class RunnableExample implements Runnable {
private String threadName;
public RunnableExample(String name) {
threadName = name;
System.out.println("创建线程: " + threadName);
}
// 线程执行的任务
public void run() {
System.out.println("启动线程: " + threadName);
try {
for (int i = 4; i > 0; i--) {
System.out.println("线程 " + threadName + ": " + i);
// 让线程暂停一段时间
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("线程 " + threadName + " 被中断");
}
System.out.println("线程 " + threadName + " 退出");
}
public static void main(String args[]) {
// 创建Runnable实例
RunnableExample R1 = new RunnableExample("线程-1");
// 创建Thread实例,并将Runnable实例作为参数传入
Thread t1 = new Thread(R1);
RunnableExample R2 = new RunnableExample("线程-2");
Thread t2 = new Thread(R2);
// 启动线程
t1.start();
t2.start();
}
}
17.2.2 继承Thread类
另一种创建线程的方式是继承Thread
类,并重写其run()
方法。接着创建该子类的实例并调用start()
方法启动线程。
/**
* 继承Thread类创建线程的示例
*/
public class ThreadExample extends Thread {
private String threadName;
public ThreadExample(String name) {
threadName = name;
System.out.println("创建线程: " + threadName);
}
// 重写run()方法,定义线程执行的任务
public void run() {
System.out.println("启动线程: " + threadName);
try {
for (int i = 4; i > 0; i--) {
System.out.println("线程 " + threadName + ": " + i);
// 让线程暂停一段时间
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("线程 " + threadName + " 被中断");
}
System.out.println("线程 " + threadName + " 退出");
}
public static void main(String args[]) {
// 创建线程实例
ThreadExample t1 = new ThreadExample("线程-1");
ThreadExample t2 = new ThreadExample("线程-2");
// 启动线程
t1.start();
t2.start();
}
}
两种方式的对比:
实现Runnable接口 | 继承Thread类 |
---|---|
能够继承其他类 | 无法再继承其他类 |
适合多个线程共享资源 | 资源共享需额外处理 |
代码结构更清晰,契合面向接口编程思想 | 代码相对简洁直接 |
17.2.3 主线程
每一个Java程序都有一个默认的主线程,也就是main()
方法所在的线程。主线程是程序的入口,负责启动其他线程。
/**
* 主线程示例
*/
public class MainThreadDemo {
public static void main(String[] args) {
// 获取当前线程(主线程)
Thread mainThread = Thread.currentThread();
System.out.println("主线程名称: " + mainThread.getName());
System.out.println("主线程优先级: " + mainThread.getPriority());
// 修改主线程名称
mainThread.setName("MyMainThread");
System.out.println("修改后主线程名称: " + mainThread.getName());
// 启动一个新线程
Thread childThread = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("子线程运行中: " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
childThread.start();
// 主线程执行任务
for (int i = 0; i < 5; i++) {
System.out.println("主线程运行中: " + i);
try {
Thread.sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("主线程执行完毕");
}
}
17.3 线程的状态与调度
17.3.1 线程的状态
Java中的线程具有以下几种状态,这些状态定义在Thread.State
枚举中:
- 新建状态(New):线程对象已创建,但尚未调用
start()
方法 - 就绪状态(Runnable):线程已启动,正在等待CPU资源
- 运行状态(Running):线程正在执行
- 阻塞状态(Blocked):线程等待锁,暂时无法运行
- 等待状态(Waiting):线程等待其他线程的特定操作
- 超时等待状态(Timed Waiting):线程在指定时间内等待
- 终止状态(Terminated):线程已完成执行
线程状态转换示例:
/**
* 线程状态示例
*/
public class ThreadStateDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
public void run() {
System.out.println("3. 线程运行中,状态: " + Thread.currentThread().getState());
try {
// 线程进入超时等待状态
Thread.sleep(1000);
// 等待另一个线程的通知
synchronized (this) {
this.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("6. 线程即将结束,状态: " + Thread.currentThread().getState());
}
});
// 新建状态
System.out.println("1. 线程创建后,状态: " + thread.getState());
// 启动线程
thread.start();
Thread.sleep(100); // 等待线程启动
System.out.println("2. 线程启动后,状态: " + thread.getState());
// 等待线程进入超时等待状态
Thread.sleep(200);
System.out.println("4. 线程休眠中,状态: " + thread.getState());
// 等待线程进入等待状态
Thread.sleep(1000);
System.out.println("5. 线程等待中,状态: " + thread.getState());
// 唤醒等待的线程
synchronized (thread) {
thread.notify();
}
// 等待线程结束
thread.join();
System.out.println("7. 线程结束后,状态: " + thread.getState());
}
}
17.3.2 线程的优先级与调度
Java线程具有优先级,范围在1到10之间,默认优先级为5。优先级较高的线程获取CPU资源的概率更大,但这并非意味着一定会先执行。
线程调度由Java虚拟机(JVM)和操作系统共同完成,Java提供了两种调度模型:
- 抢占式调度:优先级高的线程能够抢占优先级低的线程的CPU资源
-
时间片轮转:每个线程依次获取CPU时间片
/*
* 线程优先级示例
/
public class ThreadPriorityDemo {
public static void main(String[] args) {
// 创建三个线程
Thread highPriority = new Thread(new Counter("高优先级线程"));
Thread mediumPriority = new Thread(new Counter("中优先级线程"));
Thread lowPriority = new Thread(new Counter("低优先级线程"));// 设置线程优先级 highPriority.setPriority(Thread.MAX_PRIORITY); // 10 mediumPriority.setPriority(Thread.NORM_PRIORITY); // 5 lowPriority.setPriority(Thread.MIN_PRIORITY); // 1 // 启动线程 lowPriority.start(); mediumPriority.start(); highPriority.start(); } static class Counter implements Runnable { private String name; public Counter(String name) { this.name = name; } public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + ":" + i + ",优先级:" + Thread.currentThread().getPriority()); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }
}
17.3.3 控制线程的结束
线程结束的方式有以下几种:
- 自然结束:线程的
run()
方法执行完毕 - 异常结束:线程执行过程中抛出未捕获的异常
-
中断结束:调用
interrupt()
方法中断线程/*
* 线程结束控制示例
/
public class ThreadTerminationDemo {
public static void main(String[] args) throws InterruptedException {
// 创建一个可被中断的线程
Thread interruptibleThread = new Thread(new InterruptibleTask());
interruptibleThread.start();// 运行一段时间后中断线程 Thread.sleep(2000); System.out.println("主线程:请求中断子线程"); interruptibleThread.interrupt(); // 等待线程结束 interruptibleThread.join(); System.out.println("主线程:子线程已结束"); } static class InterruptibleTask implements Runnable { public void run() { try { while (!Thread.currentThread().isInterrupted()) { System.out.println("子线程:正在执行任务..."); Thread.sleep(500); // 模拟任务执行 } System.out.println("子线程:收到中断请求,准备结束"); } catch (InterruptedException e) { System.out.println("子线程:在休眠中被中断"); // 恢复中断状态 Thread.currentThread().interrupt(); } finally { System.out.println("子线程:执行清理工作"); } System.out.println("子线程:已结束"); } }
}
注意:不建议使用
stop()
、suspend()
和resume()
方法来控制线程,这些方法已被标记为过时,可能会引发资源泄露或线程死锁等问题。
17.4 线程同步与对象锁
17.4.1 线程冲突与原子操作
当多个线程访问共享资源时,若不加以控制,可能会致使数据不一致,这便是线程冲突。
原子操作指的是不可分割的操作,要么全部执行,要么都不执行。Java提供了java.util.concurrent.atomic
包来支持原子操作。
/**
* 线程冲突示例
*/
public class ThreadConflictDemo {
// 共享资源
private static int count = 0;
public static void main(String[] args) throws InterruptedException {
// 创建两个线程,同时对count进行递增操作
Thread thread1 = new Thread(new IncrementTask());
Thread thread2 = new Thread(new IncrementTask());
thread1.start();
thread2.start();
// 等待两个线程执行完毕
thread1.join();
thread2.join();
// 预期结果是20000,但实际可能小于该值
System.out.println("最终计数:" + count);
}
static class IncrementTask implements Runnable {
public void run() {
for (int i = 0; i < 10000; i++) {
// 非原子操作:读取 -> 修改 -> 写入
count++;
}
}
}
}
上述代码中,count++
并非原子操作,它包含读取count的值、将值加1、将结果写回count这三个步骤。当两个线程同时执行时,可能会导致计数不准确。
17.4.2 方法同步
运用synchronized
关键字修饰方法,能够确保同一时间仅有一个线程执行该方法,从而避免线程冲突。
/**
* 同步方法示例
*/
public class SynchronizedMethodDemo {
// 共享资源
private int count = 0;
public static void main(String[] args) throws InterruptedException {
SynchronizedMethodDemo demo = new SynchronizedMethodDemo();
// 创建两个线程,同时对count进行递增操作
Thread thread1 = new Thread(new IncrementTask(demo));
Thread thread2 = new Thread(new IncrementTask(demo));
thread1.start();
thread2.start();
// 等待两个线程执行完毕
thread1.join();
thread2.join();
// 使用同步方法后,结果应当是20000
System.out.println("最终计数:" + demo.count);
}
// 同步方法
public synchronized void increment() {
count++;
}
static class IncrementTask implements Runnable {
private SynchronizedMethodDemo demo;
public IncrementTask(SynchronizedMethodDemo demo) {
this.demo = demo;
}
public void run() {
for (int i = 0; i < 10000; i++) {
demo.increment();
}
}
}
}
对于
文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/13601.html