下面是关于semaphore 的死锁的例子。主要自己学习thinking in java 上面的semaphore的例子的时候不仔细。结果将checkout() 和 checkin() 方法都加上了synchronized. 导致了死锁的问题。代码如下:
public class SemaphoreDemo {
final static int SIZE = 10;
public static void main(String[] args) throws Exception {
final Pool<Fat> pool = new Pool<>(Fat.class, SIZE);
ExecutorService exec = Executors.newCachedThreadPool();
for(int i=0; i<SIZE; i++){
exec.execute(new CheckoutTask<Fat>(pool));
}
System.out.println("All checkout task created.");
TimeUnit.SECONDS.sleep(2);
List<Fat> list = new ArrayList<>();
for(int i=0; i<SIZE; i++){
Fat f = pool.checkout();
System.out.println(i +": main() thread checkd out");
f.operation();
list.add(f);
}
Future<?> blocked = exec.submit(new Runnable() {
@Override
public void run() {
try {
pool.checkout();//这里阻塞住了。
} catch (InterruptedException e) {
//acceptable way to exit.
}
}
});
TimeUnit.SECONDS.sleep(2);
blocked.cancel(true);//break out of blocked call.
System.out.println("checking in objects in "+list);
for(Fat f : list){
pool.checkin(f);
}
for(Fat f : list){//second check in ignored.
pool.checkin(f);
}
exec.shutdownNow();
}
}
//代理
class Pool<T> {
private int size;
//资源类型是一样的。
private List<T> holder = new ArrayList<>();
private volatile boolean[] checkedOut;//跟踪checkedout的对象。
private Semaphore avaliable;
public Pool(Class<T> resourceType, int size){
this.size = size;//这个size没有赋值,导致没有调试出来。
checkedOut = new boolean[size];
avaliable = new Semaphore(size);//permits.
//instance resources.
try{
for(int i=0; i<size; i++){
holder.add(resourceType.newInstance());
// System.out.println(holder.get(i));
}
}catch(Exception e){
throw new RuntimeException(e);
}
}
//对外提供接口
public synchronized T checkout() throws InterruptedException{
System.out.println(Thread.currentThread().getName());
avaliable.acquire();//main 在这里占用着synchronized. 但是在调用avaliable.acquire()的时候阻塞了。
return getItem();
}
public synchronized void checkin(T item){
boolean released = releaseItem(item);
if(released){
avaliable.release();
}
}
private synchronized T getItem(){
for(int i=0; i<size; i++){
if(!checkedOut[i]){
checkedOut[i] = true;
return holder.get(i);
}
}
return null;//semaphore prevents reaching here.
}
private synchronized boolean releaseItem(T item){
int index = holder.indexOf(item);
if(index == -1){
return false;
}
if(checkedOut[index]){
checkedOut[index] = false;
return true;
}
return false;
}
}
class Fat{
private static int counter = 0;
private final int id = counter++;
public Fat(){}
public void operation(){
System.out.println(this+"do operation.");
}
@Override
public String toString() {
return "id: "+id;
}
}
class CheckoutTask<T> implements Runnable{
private Pool<T> pool;
private static int counter = 0;
private final int id = counter++;
public CheckoutTask(Pool<T> pool) {
this.pool = pool;
}
@Override
public void run() {
try{
T resource = pool.checkout();
System.out.println(this+" checkedout "+ resource);
TimeUnit.SECONDS.sleep(1);
System.out.println(this+" checkedin "+resource);
pool.checkin(resource);
}catch(InterruptedException e){
}
}
@Override
public String toString() {
return "CheckoutTask "+id+" ";
}
}
死锁出现的原因是:
CheckoutTask 在执行run() 的时候,在方法的内部执行完checkout() 后 ,size 个线程都释放了checkout() 方法上的synchronized修饰的对象的锁,而此时。main ()方法中的 Fat f = pool.checkout(); 执行。由于size 个CheckoutTask 线程还在占用着Semaphore。 所以main 线程在此阻塞。但是main 线程确拿着checkout() 方法上的synchronized 修饰的对象锁。这样就形成了循环等待。即size线程占用着Semaphore ,等待main释放checkout()方法的对象锁。而main 线程占用着checkout() 方法上的对象锁,而等待着使用Semaphore。
自己的语言表达不是很好,有问题希望大家随时指教。
分享到:
相关推荐
在这个例子中,`std::lock_guard`自动管理锁的获取和释放,避免了死锁的风险。通过`mutex`,我们确保了对`shared_resource`变量的更新是原子操作,从而避免了数据竞争。 二、信号量(Semaphore) 信号量比互斥锁更...
这种机制有助于确保对共享资源的有序访问,防止数据竞争和死锁的发生。 创建一个`dispatch_semaphore`可以通过`dispatch_semaphore_create()`函数,传入一个非负整数作为初始值。这个初始值表示可以同时访问资源的...
5. 安全性与死锁预防:设计良好的同步策略能避免死锁和其他并发问题。例如,避免“资源饥饿”,确保所有核心都有机会获得资源,以及避免优先级反转。 6. 示例代码:压缩包中的代码可能包括了以上各步骤的实现,供...
在这个例子中,父子进程共享一个信号量,确保同一时间只有一个进程在执行。 **6. 注意事项** - 信号量应正确初始化和销毁,避免资源泄漏。 - 避免死锁:合理安排进程的执行顺序,防止出现无法解除的等待状态。 - ...
首先,我们来看看如何在C语言中使用`<semaphore.h>`头文件来操作信号量: 1. **创建信号量**:使用`sem_init()`函数创建一个内核级信号量。如果是在进程间共享,需要传递第三个参数为非零值。例如: ```c sem_t sem...
在编程领域,线程同步是多线程编程中的一个核心概念,它涉及到如何有效地管理和协调多个并发执行的线程,确保它们能正确地共享资源,避免数据竞争和死锁等问题。这个“线程同步小例子”是基于孙鑫先生著作中的示例...
死锁的发生往往与资源的分配顺序有关。例如,两个进程分别持有资源A和B,同时请求对方持有的资源,导致双方都无法继续,形成僵局。 信号量(Semaphore)是一种用于同步和互斥访问资源的机制。在不同情况下,设置...
线程同步用于控制不同线程对共享资源的访问,以避免数据竞争和死锁。`Mutex`、`Semaphore`、`Monitor`和`lock`关键字是常用的同步机制。这里以`lock`关键字为例: ```csharp using System; using System.Threading;...
C#线程同步是多线程编程中的一个重要概念,它涉及到如何控制多个线程对共享资源的访问,以避免数据不...通过实践和调试这些典型的C#线程同步例子,你可以深入理解各种同步机制的工作方式,并学会在实际项目中灵活运用。
3. **线程同步与通信**:如果需要,还可能涉及线程间的同步操作,如使用`WaitForSingleObject`、`Mutex`、`Semaphore`或`Event`等工具,以确保线程间的正确协作和资源访问。 4. **线程退出与资源清理**:当线程执行...
此外,还有Semaphore(信号量)用于限制同时访问特定资源的线程数量,CountDownLatch和CyclicBarrier用于多线程间的协作。 在实际开发中,我们还会遇到线程池的概念。Java的ExecutorService和ThreadPoolExecutor提供...
4. **同步机制**:为了防止多个线程对共享资源的不正确访问,Java提供了多种同步机制,如`synchronized`关键字、`Lock`接口以及相关的同步工具类(如`Semaphore`信号量)。在这个例子中,包子的数量可能是共享资源,...
在多线程编程中,线程间的同步至关重要,以避免数据竞争和死锁等问题。Win32 API 提供了多种同步机制: 1. 互斥量(Mutex):保证同一时间只有一个线程能访问特定资源。 2. 信号量(Semaphore):控制对有限资源的...
正确理解和使用它们可以提高程序的并发性能,同时避免数据竞争和死锁等问题。通过Windows API或C++标准库提供的工具,我们可以方便地在C++中实现线程和线程锁的功能。在实际项目中,根据具体需求选择合适的同步机制...
上述代码展示了死锁的一个经典例子,涉及到两个类A和B,它们各自拥有一个同步方法foo()和bar(),以及一个last()方法。在Deadlock类中,主线程获取了A的锁并尝试调用B的last()方法,而另一个线程则获取了B的锁并尝试...
多线程在C#中主要通过`System.Threading`命名空间实现,包括`Thread`类、`Mutex`、`Semaphore`、`Monitor`等同步机制。开发者可能使用了`ThreadPool`或者`Task`来管理线程,这些在`Form1.cs`中应该有具体的实现。...
`Mutex`、`Semaphore`和`Monitor`等工具可以帮助我们控制对共享资源的访问,防止竞态条件和死锁的发生。例如,使用`Mutex`可以确保同一时间只有一个线程访问特定资源: ```vbnet Dim sharedResourceMutex As New ...
虽然这个例子展示了基本的线程同步,但实际的多线程编程中还需要考虑更复杂的并发问题,如死锁和竞态条件。死锁发生在两个或更多线程相互等待对方释放资源而无法继续执行的情况。竞态条件是指多个线程对共享变量的...
这本书“Java并发编程实践中(中+英+例子源码)”提供了深入理解Java并发机制的宝贵资源。下面我们将详细探讨其中涉及的一些关键知识点。 1. **线程与进程**:在并发编程中,线程是程序执行的基本单位,而进程则是...