Java中常见的并发控制手段浅析
在多线程编程中,为了避免线程之间的冲突和竞争,需要使用并发控制手段来确保线程安全。Java提供了多种并发控制手段,本文将对其进行浅析。
synchronized
synchronized
是Java中最基本的并发控制手段之一,它通过对对象或方法进行加锁,确保同一时间内只有一个线程可以访问被锁定的资源。它主要有以下几种用法:
- 对象锁:使用
synchronized
对某个对象进行加锁,例如:
```java
public class MyRunnable implements Runnable {
private final Object lock = new Object();
public void run() {
synchronized(lock) {
// ...
}
}
}
```
- 类锁:使用
synchronized
对某个类进行加锁,例如:
java
public class MyClass {
public static synchronized void myMethod() {
// ...
}
}
- 方法锁:直接在方法上加
synchronized
,例如:
java
public class MyClass {
public synchronized void myMethod() {
// ...
}
}
然而,虽然synchronized
很好用,但却有一些问题。其中最大的问题是它会造成死锁,而死锁是一个非常严重的问题。
ReentrantLock
ReentrantLock
是synchronized
的替代品,它也是一个互斥锁,可以用来控制多线程对共享资源的访问。与synchronized
不同的是,它可以实现公平锁或非公平锁,还可以打断正在等待锁的线程,避免死锁的发生。使用ReentrantLock
的基本代码如下:
public class MyRunnable implements Runnable {
private final ReentrantLock lock = new ReentrantLock();
public void run() {
lock.lock();
try {
// ...
} finally {
lock.unlock();
}
}
}
Semaphore
Semaphore
是一种控制并发访问的手段,它可以控制同时访问某个资源的线程数量。例如,我们可以使用一个Semaphore
来保证数据库连接池里的连接数量不超过10个。
public class ConnectionPool {
private final Semaphore semaphore = new Semaphore(10);
public Connection getConnection() {
semaphore.acquire();
// 获取连接的代码
return new Connection();
}
public void releaseConnection(Connection conn) {
// 释放连接的代码
semaphore.release();
}
}
示例1:使用Semaphore控制线程数量
下面是一个示例代码,其中10个线程会竞争3个资源:
public class MyRunnable implements Runnable {
private final Semaphore semaphore = new Semaphore(3);
public void run() {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " acquire semaphore");
Thread.sleep(1000);
semaphore.release();
System.out.println(Thread.currentThread().getName() + " release semaphore");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(10);
MyRunnable runnable = new MyRunnable();
for (int i = 0; i < 10; i++) {
executor.submit(runnable);
}
executor.shutdown();
}
}
在这个示例中,只能同时有3个线程处于运行状态,其余线程会被阻塞,等待资源的释放。
示例2:使用ReentrantLock实现公平锁和非公平锁
ReentrantLock
可以实现公平锁和非公平锁。公平锁会按照线程请求的先后顺序获取锁,而非公平锁则不会,它会有利于吞吐量的提升。下面是实现公平锁和非公平锁的示例:
public class MyRunnable implements Runnable {
private final ReentrantLock lock = new ReentrantLock(true); // 公平锁
// private final ReentrantLock lock = new ReentrantLock(false); // 非公平锁
public void run() {
lock.lock();
try {
// ...
} finally {
lock.unlock();
}
}
}
在这个示例中,当使用公平锁时,线程会按照它们请求锁的先后顺序获得它们的访问时间。如果使用非公平锁,有可能让某些线程比其他线程更频繁地获得访问。
结论
本文简单介绍了Java中常见的并发控制手段:synchronized
、ReentrantLock
和Semaphore
。当然,这还远远不是全部,更多的控制手段需要根据实际情况选择合适的方式。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中常见的并发控制手段浅析 - Python技术站