始终获取唯一ID并将其释放以供重复使用

时间:2012-08-18 04:05:50

标签: java multithreading threadpoolexecutor

ExecutorService service = new ThreadPoolExecutor(10, 10, 1000L,
    TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(10, true), new 
    ThreadPoolExecutor.CallerRunsPolicy());

问题陈述是: -

每个帖子在unique ID之间使用1 and 1000,程序必须在60 minutes or more之间运行,在我的run method中,当我做id as zero时我几次(if(id==0)) { {1}}检查并将断点置于该循环下,我不知道为什么?由于availableExistingIds的值介于1和1000之间,因此我不知道这个zero is coming in my id在哪里?

class IdPool {
    private final LinkedList<Integer> availableExistingIds = new LinkedList<Integer>();

    public IdPool() {
        for (int i = 1; i <= 1000; i++) {
            availableExistingIds.add(i);
        }
    }

    public synchronized Integer getExistingId() {
        return availableExistingIds.removeFirst();
    }

    public synchronized void releaseExistingId(Integer id) {
        availableExistingIds.add(id);
    }
}


class ThreadNewTask implements Runnable {
    private IdPool idPool;
    private int id;

    public ThreadNewTask(IdPool idPool) {
        this.idPool = idPool;
    }

    public void run() {
        try {
        id = idPool.getExistingId();
    //Anything wrong here?  
                if(id==0) {
        System.out.println("Found Zero");
        }
        someMethod(id);
        } catch (Exception e) {
        System.out.println(e);
        } finally {
        idPool.releaseExistingId(id);
        }
    }

// This method needs to be synchronized or not?
    private synchronized void someMethod(Integer id) {
        System.out.println("Task: " +id);
// and do other calcuations whatever you need to do in your program
    }
}

以下是程序开始的主要类 -

public class TestingPool {
    public static void main(String[] args) throws InterruptedException {
        int size = 10;
        int durationOfRun = 60;
        IdPool idPool = new IdPool();   
        // create thread pool with given size
        ExecutorService service = new ThreadPoolExecutor(size, size, 500L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(size), new ThreadPoolExecutor.CallerRunsPolicy()); 

        // queue some tasks
        long startTime = System.currentTimeMillis();
        long endTime = startTime + (durationOfRun * 60 * 1000L);

        // Running it for 60 minutes
        while(System.currentTimeMillis() <= endTime) {
            service.submit(new ThreadNewTask(idPool));
        }

        // wait for termination        
        service.shutdown();
        service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); 
    }
}

更新: -

我想在这里使用ArrayBlockingQueue,这样当没有可用的id时它会等待崩溃,而是等待一个可用。任何人都可以建议我如何在这里使用它?

实施BlockingQueue后的代码更改。

public void run() {
    System.err.println(command.getDataCriteria());
    if(command.getDataCriteria().equals(PDSLnPConstants.DATA_CRITERIA_PREVIOUS)) {
    try {
        System.out.println(command.getDataCriteria());
        // Getting existing id from the pool
        existId = existPool.take();
        attributeGetSetMethod(existId);
    } catch (Exception e) {
        getLogger().log(LogLevel.ERROR, e.getLocalizedMessage());
    } finally {
        // And releasing that existing ID for re-use
        existPool.offer(existId);       
    }
    } 


else if(command.getDataCriteria().equals(PDSLnPConstants.DATA_CRITERIA_NEW)) {
    try {
        System.out.println(command.getDataCriteria());
        // Getting new id from the pool
        newId = newPool.take();
        attributeGetSetMethod(newId);
    } catch (Exception e) {
        getLogger().log(LogLevel.ERROR, e.getLocalizedMessage());
    } finally {
        // And releasing that new ID for re-use
        newPool.offer(newId);   
    }
    }
}

我刚才注意到的一个奇怪的事情是 - 如果你在else if loop中看到我的上述代码run method,那么command.getDataCriteria() is Previous中的上述代码也会在else if block(which is for New)中输入.equals check我应该做else if(command.getDataCriteria().equals(PDSLnPConstants.DATA_CRITERIA_NEW)) { 这不应该发生什么?为什么会这样?

{{1}}

2 个答案:

答案 0 :(得分:1)

您可以获得id = 0的一种情况(除了由于您不使用同步而导致未定义行为的可能性)是id池耗尽(空)。当发生这种情况时,行:

id = idPool.getExistingId();

将因NoSuchElementException而失败。在这种情况下,finally块将运行:

idPool.releaseExistingId(id);

但由于第一行失败,id的默认值仍为0。所以你最终“释放”0并将其添加回id池,即使它从未在池中开始。然后,后面的任务可以合法地0

但是,这肯定会在catch块中打印你的异常。

答案 1 :(得分:0)

Java提供(自Java 5起)Semaphore,我相信你正在关注counting semaphore