Java 每个线程使用唯一的ID并释放它以供重用

Java 每个线程使用唯一的ID并释放它以供重用,java,multithreading,synchronization,Java,Multithreading,Synchronization,下面是代码,在运行方法中,我总是试图从可用的现有id中获取唯一id,并通过创建链表顺序同时释放它,但在某些情况下我发现,我得到了NoTouchElementException,id是零次,我认为这在任何时候都不会发生 class IdPool { private final LinkedList<Integer> availableExistingIds = new LinkedList<Integer>(); public IdPool() {

下面是代码,在
运行方法
中,我总是试图从可用的现有id中获取
唯一id,并通过创建
链表顺序
同时释放它,但在某些情况下我发现,我得到了
NoTouchElementException
,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
            }
}
将失败,出现
NoTouchElementException
。在这种情况下,finally块将运行:

idPool.releaseExistingId(id);

但由于第一行失败,id的默认值仍为0。因此,我最终“释放”
0
,并将其添加回id池,即使它从一开始就不在池中。然后,以后的任务可能会合法地占用0。这就是我不需要的。有人能在我的代码中建议我如何克服这种情况吗?我一直希望id应该在
1到1000范围内

为什么不修改代码,以便在没有可用id时,它不会崩溃,而是等待一个id变为可用

否则,每次您有太多的线程同时工作时,池将耗尽,您将不得不处理大量失败的线程。同步工作也会自动为您处理

编辑:这是修改后的代码

class ThreadNewTask implements Runnable {
  private BlockingQueue<Integer> pool;
  private int id;

  public ThreadNewTask(BlockingQueue<Integer> pool) {
    this.pool = pool;
  }

  public void run() {
    try {
        id = pool.take();
        someMethod(id);
    } catch (Exception e) {
        System.out.println(e);
    } finally {
        pool.offer(id);
    }
  }

  private void someMethod(Integer id) {
    System.out.println("Task: " +id);
            // and do other calcuations whatever you need to do in your program
  }
}  
类ThreadNewTask实现可运行{
私有阻塞队列池;
私有int-id;
公共线程任务(阻止队列池){
this.pool=pool;
}
公开募捐{
试一试{
id=pool.take();
方法(id);
}捕获(例外e){
系统输出打印ln(e);
}最后{
联合报价(id);
}
}
私有方法(整数id){
System.out.println(“任务:+id”);
//在你的程序中做任何你需要做的计算
}
}  
然后用如下方式初始化池:

LinkedList<Integer> availableExistingIds = new LinkedList<Integer>();
for (int i = 1; i <= 1000; i++) {
  availableExistingIds.add(i);
}
BlockingQueue<Integer> pool = new ArrayBlockingQueue<Integer>(1000, false, availableExistingIds);
LinkedList availableExistingIds=new LinkedList();

对于(inti=1;i为什么不修改代码,以便在没有可用ID时不会崩溃,而是等待一个ID变为可用

否则,每次有太多线程同时工作时,池就会耗尽,您将不得不处理大量失败的线程。同步工作也会自动为您处理

编辑:这是修改后的代码

class ThreadNewTask implements Runnable {
  private BlockingQueue<Integer> pool;
  private int id;

  public ThreadNewTask(BlockingQueue<Integer> pool) {
    this.pool = pool;
  }

  public void run() {
    try {
        id = pool.take();
        someMethod(id);
    } catch (Exception e) {
        System.out.println(e);
    } finally {
        pool.offer(id);
    }
  }

  private void someMethod(Integer id) {
    System.out.println("Task: " +id);
            // and do other calcuations whatever you need to do in your program
  }
}  
类ThreadNewTask实现可运行{
私有阻塞队列池;
私有int-id;
公共线程任务(阻止队列池){
this.pool=pool;
}
公开募捐{
试一试{
id=pool.take();
方法(id);
}捕获(例外e){
系统输出打印ln(e);
}最后{
联合报价(id);
}
}
私有方法(整数id){
System.out.println(“任务:+id”);
//在你的程序中做任何你需要做的计算
}
}  
然后用如下方式初始化池:

LinkedList<Integer> availableExistingIds = new LinkedList<Integer>();
for (int i = 1; i <= 1000; i++) {
  availableExistingIds.add(i);
}
BlockingQueue<Integer> pool = new ArrayBlockingQueue<Integer>(1000, false, availableExistingIds);
LinkedList availableExistingIds=new LinkedList();

对于(int i=1;我感谢Mario的建议。这对我来说很有意义。你能根据你的建议编辑我的代码吗?这将非常有帮助,因为我刚刚开始学习多线程,ArrayBlockingQueue的概念对我来说是一个新概念。这样我就可以理解如何一次性使用所有这些东西。谢谢。在我的例子中,
可用存在我ds
不是整数,它是一个
LinkedList
感谢Mario的编辑,当我尝试同样的事情时,我得到了类似这样的东西-
构造函数ArrayBlockingQueue(LinkedList)是未定义的
,建议我将
可用的现有ID的类型更改为int
。为什么会这样?你是对的,构造函数实际上是
公共ArrayBlockingQueue(int capacity,boolean fair,CollectionYup..谢谢你让我讲清楚。
ArrayBlockingQueue
的容量应该始终与
availableExistingIds
的大小相同,因此在我们的例子中,容量应该始终与
availableExistingIds
的大小相同,即
1000
?感谢Mario的建议。我的意思是这对我来说很有意义。你能根据你的建议编辑我的代码吗?这将非常有帮助,因为我刚开始学习多线程和ArrayBlockingQueue的概念对我来说是新概念。这样我就可以理解如何一次性使用所有这些东西。谢谢。在我的例子中,可用的现有ID
不是整数,而是
链接列表
感谢Mario的编辑,当我尝试同样的方法时,我得到了类似这样的结果-
构造函数ArrayBlockingQueue(LinkedList)是未定义的
,它建议我将可用的现有ID的类型更改为int
。为什么会这样?你是对的,构造函数实际上是
公共ArrayBlockingQueue(int capacity,boolean fair,CollectionYup..谢谢你让我讲清楚。因此,
ArrayBlockingQueue
的容量应该始终与
availableExistingIds
的大小相同,因此在我们的例子中,容量应该始终与
availableExistingIds
的大小相同,即
1000