Java多线程编程
# Java多线程编程
Java多线程编程是指在一个进程中创建多个线程,使得程序能够同时运行多个任务。Java多线程编程的优点是可以充分利用多核CPU的优势,提高程序的运行效率。
Java多线程编程的基本概念:
- 进程:进程是操作系统分配资源的最小单位,每个进程都有自己的内存空间、代码段、数据段。
- 线程:线程是程序执行的最小单位,每个线程都有自己的执行路径和资源。
- 线程的创建:在Java中,可以通过继承Thread类或者实现Runnable接口来创建线程。
- 线程的调度:线程调度是指系统按照一定的规则,将可运行的线程分配给CPU执行。Java线程调度采用抢占式调度策略,即优先级高的线程优先执行。
- 线程的同步:同步是指多个线程共同访问一个资源,为了保证数据的一致性,需要对共享资源进行同步。
- 线程的死锁:死锁是指两个或多个线程互相等待对方占用的资源,导致程序无法继续运行。
Java多线程编程的常用类:
- Thread类:Thread类是Java多线程编程的基础类,用于创建和控制线程。
- Runnable接口:Runnable接口是Java多线程编程的另一种方式,用于创建线程。
- Executor框架:Executor框架是Java提供的线程池,用于简化线程的创建和管理。
- Future接口:Future接口用于获取线程执行结果。
- Synchronized关键字:Synchronized关键字用于在多线程环境下对共享资源进行同步。
- Lock接口:Lock接口是Java提供的用于替代Synchronized关键字的接口。
- 线程间通信:Java多线程编程中,线程间通信主要有两种方式:共享内存和消息传递。
# 创建线程
在Java中,可以通过继承Thread类或者实现Runnable接口来创建线程。
# 继承Thread类创建线程
public class MyThread extends Thread {
@Override
public void run() {
// 线程执行的代码
}
}
2
3
4
5
6
# 实现Runnable接口创建线程
public class MyThread implements Runnable {
@Override
public void run() {
// 线程执行的代码
}
}
2
3
4
5
6
# 通过ThreadExecutor框架创建线程池
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executor.execute(new MyThread());
}
executor.shutdown();
}
}
2
3
4
5
6
7
8
9
# 通过ExecutorService创建线程池
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executor.execute(new MyThread());
}
executor.shutdown();
}
}
2
3
4
5
6
7
8
9
# 常用方法
# start()方法
start()方法用于启动线程,调用start()方法后,线程进入就绪状态,等待CPU调度执行。
Thread thread = new Thread(new MyThread());
thread.start();
2
# run()方法
run()方法用于定义线程执行的代码,当线程启动后,会自动调用run()方法。
public class MyThread implements Runnable {
@Override
public void run() {
// 线程执行的代码
}
}
2
3
4
5
6
# sleep()方法
sleep()方法用于使线程暂停执行一段时间,单位为毫秒。
Thread.sleep(1000); // 暂停1秒
# yield()方法
yield()方法用于让出CPU资源,让其他线程有机会执行。
Thread.yield();
# join()方法
join()方法用于等待线程执行完毕,可以指定等待的时间。
Thread thread = new Thread(new MyThread());
thread.start();
thread.join(); // 等待线程执行完毕
2
3
# isAlive()方法
isAlive()方法用于判断线程是否存活。
if (thread.isAlive()) {
// 线程存活
} else {
// 线程已死
}
2
3
4
5
# interrupt()方法
interrupt()方法用于中断线程的执行。
Thread thread = new Thread(new MyThread());
thread.start();
thread.interrupt(); // 中断线程的执行
2
3
# 线程状态
Java线程有6种状态:
- 新建状态(New):线程被创建,但还没有开始执行。
- 就绪状态(Runnable):线程已启动,但还没有获得CPU资源。
- 运行状态(Running):线程获得了CPU资源,正在执行。
- 阻塞状态(Blocked):线程在等待一个事件,比如等待IO操作完成。
- 死亡状态(Dead):线程执行完毕。
- 等待状态(Waiting):线程在等待另一个线程执行某个操作。
可以通过getState()方法获取线程的状态。
Thread.State state = thread.getState();
# 线程调度
Java线程调度采用抢占式调度策略,即优先级高的线程优先执行。可以通过设置线程的优先级来调整线程的执行顺序。
Thread thread = new Thread(new MyThread());
thread.setPriority(Thread.MAX_PRIORITY); // 设置线程优先级为最大值
thread.start();
2
3
# 线程同步
同步是指多个线程共同访问一个资源,为了保证数据的一致性,需要对共享资源进行同步。Java中提供了多种同步机制,包括synchronized关键字、Lock接口、volatile关键字等。
# synchronized关键字
synchronized关键字用于在多线程环境下对共享资源进行同步。
public class MyThread extends Thread {
private int count = 0;
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
synchronized (this) {
count++;
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
# Lock接口
Lock接口是Java提供的用于替代Synchronized关键字的接口。
public class MyThread extends Thread {
private int count = 0;
private Lock lock = new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 线程间通信
Java多线程编程中,线程间通信主要有两种方式:共享内存和消息传递。
# 共享内存
共享内存是指多个线程共同访问同一块内存空间,通过读写内存中的数据进行通信。
public class MyThread extends Thread {
private int count = 0;
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
count++;
}
}
}
2
3
4
5
6
7
8
9
10
# 消息传递
消息传递是指多个线程通过队列或管道等方式进行通信。
public class MyThread extends Thread {
private int count = 0;
private Queue<Integer> queue = new LinkedList<>();
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
queue.offer(i);
}
}
}
2
3
4
5
6
7
8
9
10
11
# 线程池
线程池是一种用于管理和复用线程的技术,可以提高程序的性能和资源利用率。Java提供了Executor框架来创建和管理线程池。
public class MyThread extends Thread {
private int count = 0;
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
count++;
}
}
}
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
executor.execute(new MyThread());
}
executor.shutdown();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 线程安全
线程安全是指多个线程访问同一资源时,资源的状态不会被其他线程破坏。Java中提供了多种线程安全机制,包括原子操作、加锁、线程本地存储、锁的顺序性等。
# 原子操作
原子操作是指一个不可分割的操作,要么全部执行,要么全部不执行。Java中提供了Atomic包来提供原子操作。
public class MyThread extends Thread {
private AtomicInteger count = new AtomicInteger(0);
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
count.incrementAndGet();
}
}
}
2
3
4
5
6
7
8
9
10
# 加锁
加锁是指通过锁机制来保证多个线程访问共享资源时的互斥性。Java中提供了synchronized关键字和Lock接口来加锁。
public class MyThread extends Thread {
private int count = 0;
private Lock lock = new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 线程本地存储
线程本地存储是指每个线程都有自己的数据副本,互不干扰。Java中提供了ThreadLocal类来实现线程本地存储。
public class MyThread extends Thread {
private static ThreadLocal<Integer> count = new ThreadLocal<>();
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
count.set(i);
}
}
}
2
3
4
5
6
7
8
9
10
# 锁的顺序性
锁的顺序性是指多个线程按照锁的申请顺序来获取锁,确保线程间的同步。Java中提供了ReentrantLock类来实现锁的顺序性。
public class MyThread extends Thread {
private int count = 0;
private Lock lock = new ReentrantLock();
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 死锁
死锁是指两个或多个线程互相等待对方占用的资源,导致程序无法继续运行。Java中提供了Thread.holdsLock()方法来检测线程是否持有某个锁。
public class MyThread extends Thread {
private int count = 0;
private Lock lock1 = new ReentrantLock();
private Lock lock2 = new ReentrantLock();
@Override
public void run() {
lock1.lock();
try {
lock2.lock();
try {
count++;
} finally {
lock2.unlock();
}
} finally {
lock1.unlock();
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20