下面是关于semaphore 的死锁的例子。主要自己学习thinking in java 上面的semaphore的例子的时候不仔细。结果将checkout() 和 checkin() 方法都加上了synchronized. 导致了死锁的问题。代码如下:
死锁出现的原因是:
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。
自己的语言表达不是很好,有问题希望大家随时指教。
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。
自己的语言表达不是很好,有问题希望大家随时指教。