引言
在多核处理器日益普及的今天,充分利用多核资源提升程序性能已成为软件开发的重要方向。Java多线程编程作为实现并发和并行处理的核心技术,对于提高程序运行效率、优化资源利用具有重要意义。本教程旨在从零开始,全面、系统地讲解Java多线程编程的各个方面,包括线程基础、同步机制、并发工具、性能优化等内容,帮助读者掌握多线程编程的核心技能。
一、线程基础
1.1 线程的概念
线程是操作系统能够进行运算调度的最小单位,是进程中的一条执行路径。一个进程可以包含多个线程,这些线程共享进程的资源,如内存空间和文件句柄,但拥有各自独立的栈空间和程序计数器。
1.2 线程的创建
在Java中,创建线程主要有两种方式:继承Thread
类和实现Runnable
接口。
1.2.1 继承Thread
类
通过继承Thread
类并重写run()
方法,可以创建一个线程。
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程运行中");
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动线程
}
}
1.2.2 实现Runnable
接口
实现Runnable
接口并传入Thread
类的构造函数,也是创建线程的常见方式。这种方式更灵活,因为Java不支持多重继承,但可以实现多个接口。
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程运行中");
}
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();
}
}
线1.3 线程的生命周期
线程的生命周期包括以下几个阶段:
- 新建(New):线程对象被创建,但尚未启动。
- 就绪(Runnable):线程已经启动,正在等待获取CPU资源。
- 运行(Running):线程获得了CPU资源,正在执行。
- 阻塞(Blocked):线程由于某种原因(如等待I/O操作完成)暂停执行。
- 死亡(Dead):线程执行完毕或由于异常退出。
1.4 线程的启动与终止
1.4.1 启动线程
通过调用Thread
对象的start()
方法启动线程。start()
方法会调用线程的run()
方法,使线程进入就绪状态。
1.4.2 终止线程
线程在执行完run()
方法后会自动终止。如果需要提前终止线程,可以通过设置标志位或使用interrupt()
方法。
public class MyThread extends Thread {
private volatile boolean running = true;
@Override
public void run() {
while (running) {
// 执行任务
}
}
public void stopThread() {
running = false;
}
}
使用interrupt()
方法:
public class MyThread extends Thread {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
// 执行任务
}
}
}
// 在另一个线程中调用interrupt()
thread.interrupt();
1.5 线程的优先级
Java线程可以设置优先级,优先级高的线程在竞争CPU资源时可能获得更多机会。优先级范围从1到10,默认优先级为5。
Thread thread = new Thread(runnable);
thread.setPriority(Thread.MAX_PRIORITY); // 设置最高优先级
1.6 线程的休眠与唤醒
1.6.1 休眠线程
通过Thread.sleep(long millis)
方法可以使线程休眠指定的毫秒数。
try {
Thread.sleep(1000); // 休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
1.6.2 唤醒线程
sleep()
方法会使线程进入阻塞状态,当休眠时间结束后,线程会自动唤醒。也可以通过interrupt()
方法唤醒休眠中的线程,此时会抛出InterruptedException
。
1.7 线程的让步
Thread.yield()
方法可以使当前线程主动让出CPU资源,让其他线程有机会执行。但yield()
方法只是提示调度器,并不保证线程一定会让出CPU。
Thread.yield();
1.8 线程的合并
Thread.join()
方法可以使当前线程等待另一个线程执行完毕后再继续执行。
Thread thread = new Thread(runnable);
thread.start();
try {
thread.join(); // 等待thread执行完毕
} catch (InterruptedException e) {
e.printStackTrace();
}
二、线程同步与通信
在多线程环境中,多个线程可能同时访问共享资源,导致数据不一致等问题。线程同步与通信机制用于解决这些问题,确保线程安全。
2.1 同步方法
使用synchronized
关键字修饰方法,可以保证同一时间只有一个线程执行该方法。
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
2.2 同步代码块
使用synchronized
关键字修饰代码块,可以指定锁对象,实现更细粒度的同步。
public class Counter {
private int count = 0;
private final Object lock = new Object();
public void increment() {
synchronized (lock) {
count++;
}
}
public int getCount() {
synchronized (lock) {
return count;
}
}
}
2.3 锁对象
Java提供了Lock
接口及其实现类ReentrantLock
,提供更灵活的锁机制。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private int count = 0;
private final Lock lock = new ReentrantLock();
public void increment() {