Java 多线程同步的几种方法
在多线程编程中,多个线程同时访问共享资源时,容易出现数据竞争的情况,为了实现线程安全,需要使用同步机制。Java 提供了多种同步机制,本文将详细介绍 Java 多线程的同步几种方法。
1. synchronized 关键字
synchronized
关键字可以保证同一时刻只有一个线程可以执行某个方法或代码块,从而避免多个线程同时访问同一个共享资源时发生的不一致问题。synchronized
可以用在方法声明上或者代码块中。
在方法声明上使用 synchronized 关键字
public synchronized void test() {
// todo something
}
上面的代码表示 test()
方法是线程安全的,任何线程都无法同时调用这个方法。
在代码块中使用 synchronized 关键字
public void test() {
synchronized(this) {
// todo something
}
}
上面代码表示 test()
方法内部的代码块是线程安全的,任何时间只会有一个线程执行该代码块。
2. ReentrantLock 锁
ReentrantLock
是一个可重入的互斥锁,与 synchronized
关键字一样,它能够解决多个线程访问同一个共享资源的问题。但是相比于 synchronized
,ReentrantLock
提供了更加灵活和强大的控制。
使用 ReentrantLock 的基本用法
Lock lock = new ReentrantLock();
lock.lock(); // 获取锁
try {
// todo something
} finally {
lock.unlock(); // 释放锁
}
上面的代码表示,多个线程调用同一个代码时,只有一个线程持有锁,其他线程只能阻塞等待锁的释放。
ReentrantLock 的高级用法
ReentrantLock
还有很多高级用法,比如可以支持公平锁或非公平锁,支持多个条件变量等。
Lock lock = new ReentrantLock(true); // 使用公平锁
Condition condition = lock.newCondition(); // 创建条件变量
lock.lock(); // 获取锁
try {
while (!conditionTrue) {
condition.await(); // 等待条件变量
}
// todo something
condition.signal(); // 唤醒线程,通知条件变量已经满足
} finally {
lock.unlock(); // 释放锁
}
上面的代码表示,使用 ReentrantLock
可以更加灵活的控制线程的运行,例如支持公平锁或非公平锁,以及支持多个条件变量,通过条件变量唤醒正在等待的线程。
3. volatile 关键字
volatile
关键字通常用于多线程并发访问共享变量,它可以确保多个线程可以正确的访问一个共享变量,同时避免因为编译器的优化而导致的问题。
public class VolatileDemo {
private volatile boolean flag;
public void test() {
flag = true;
}
}
上面的代码中,当一个线程调用 test()
方法时将 flag
设置为 true
,如果 flag
是非 volatile
型变量,那么另一个线程可能不会读到 flag
的更新,因为编译器优化可能会将 flag
cache 到线程的本地变量中。
4. AtomicInteger 类
AtomicInteger
类是一个原子类,它提供了原子性操作,能够保证对共享变量进行操作时不会同时被多个线程读写。
public class AtomicIntegerDemo {
private AtomicInteger count;
public AtomicIntegerDemo() {
count = new AtomicInteger(0);
}
public void increment() {
count.incrementAndGet(); // 原子性自增操作
}
}
上面的代码中,count
的值是原子性操作,可以确保多个线程同时对 count
计数时不会发生冲突问题。
示例说明
下面是一个使用 synchronized
关键字实现的示例:
public class SynchronizedDemo {
private int count;
public synchronized void increment() {
count++;
}
}
上面的代码中,increment()
方法是线程安全的,任何线程只能有一个线程访问该方法。
下面是一个使用 ReentrantLock
锁实现的示例:
public class LockDemo {
private Lock lock;
private int count;
public LockDemo() {
lock = new ReentrantLock();
count = 0;
}
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
上面的代码中,使用了 ReentrantLock
实现对 count
值的原子性操作。
总之,以上这些方法都是 Java 中常见的多线程同步方法,通过适当的选择不同的同步方法,可以让程序在保证正常运行的同时充分发挥多核 CPU 的性能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java 多线程的同步几种方法 - Python技术站