synchronized
在Java中,使用synchronized关键字可以实现对代码块或方法的同步访问,以确保多个线程不会同时访问共享资源。当一个线程获取了对象的锁(即进入了synchronized代码块),其他线程如果也希望获取该对象的锁,它们将被阻塞,直到拥有锁的线程执行完毕并释放锁。
因此,在某种意义上,使用synchronized关键字可以导致线程阻塞。这是因为当一个线程持有锁时,其他线程在尝试获得相同锁时将会被阻塞,直到持有锁的线程释放锁。
然而,需要注意的是,线程阻塞并不是synchronized关键字的本质特性,而是由于锁的竞争和获取导致的一种现象。synchronized关键字的作用是确保对共享资源的安全访问,而阻塞是由于多个线程对锁的竞争导致的。
在实际编码中,应该谨慎地使用synchronized关键字,避免出现过多的锁竞争,从而导致性能问题和线程阻塞。同时,还可以考虑使用更灵活的并发控制工具,如ReentrantLock、Semaphore等,来避免一些synchronized可能引起的问题。
ReentrantLock
ReentrantLock是Java中的一个可重入锁(Reentrant Lock),它提供了与synchronized关键字类似的功能,但更加灵活和扩展。
与synchronized关键字不同,ReentrantLock允许线程多次获取同一个锁,而不会导致死锁。它使用计数器来跟踪锁的持有次数,每次获取锁时计数器加一,释放锁时计数器减一。只有当计数器为零时,其他线程才能获取该锁。
下面是一个简单的示例,演示了如何使用ReentrantLock来控制并发访问:
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
Runnable task = () -> {
try {
lock.lock(); // 获取锁
// 访问共享资源的代码
System.out.println("Thread " + Thread.currentThread().getId() + " is accessing the shared resource");
Thread.sleep(2000); // 模拟访问共享资源的耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // 释放锁
}
};
// 创建多个线程并启动
for (int i = 0; i < 5; i++) {
new Thread(task).start();
}
}
}
在这个示例中,我们创建了一个ReentrantLock实例,并在多个线程中使用lock()方法获取锁,并在访问共享资源后使用unlock()方法释放锁。
与synchronized关键字相比,ReentrantLock提供了更多的功能,比如可定时的、可中断的锁等待机制、公平性等。但需要注意的是,使用ReentrantLock需要显式地调用lock()和unlock()方法来控制锁的获取和释放,确保在异常情况下锁能够被正确释放,否则可能导致死锁。
总的来说,ReentrantLock是一种强大而灵活的锁实现,可以在需要更复杂的并发控制时使用,提供了比synchronized更多的功能选项。
Semaphore
Semaphore是Java中用于控制并发访问的工具之一,它可以限制对共享资源的访问数量。与synchronized关键字不同,Semaphore允许多个线程同时访问共享资源,但是通过控制许可证的数量来限制并发访问的线程数。
Semaphore维护了一定数量的许可证(permits),线程在访问共享资源之前必须先获得许可证,如果许可证数量耗尽,其他线程将被阻塞直到有线程释放许可证。
下面是一个简单的示例,演示了如何使用Semaphore来控制并发访问:
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2); // 创建一个初始许可证数量为2的Semaphore
Runnable task = () -> {
try {
semaphore.acquire(); // 获取许可证
// 访问共享资源的代码
System.out.println("Thread " + Thread.currentThread().getId() + " is accessing the shared resource");
Thread.sleep(2000); // 模拟访问共享资源的耗时操作
semaphore.release(); // 释放许可证
} catch (InterruptedException e) {
e.printStackTrace();
}
};
// 创建多个线程并启动
for (int i = 0; i < 5; i++) {
new Thread(task).start();
}
}
}
在这个示例中,我们创建了一个初始许可证数量为2的Semaphore,然后创建了5个线程尝试访问共享资源。由于Semaphore的许可证数量限制为2,只有两个线程可以同时获得许可证并访问共享资源,其他线程将会被阻塞。
总的来说,Semaphore提供了比synchronized更灵活、更细粒度的并发访问控制,可以帮助我们更好地管理共享资源的访问,并避免一些潜在的性能问题。
标签:Java,Thread,synchronized,ReentrantLock,线程,访问共享,Semaphore From: https://www.cnblogs.com/xianfengzhike/p/17886962.html