Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/380.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java生产者消费者ArrayBlockingQueue在take()上发生死锁_Java_Multithreading_Blockingqueue - Fatal编程技术网

Java生产者消费者ArrayBlockingQueue在take()上发生死锁

Java生产者消费者ArrayBlockingQueue在take()上发生死锁,java,multithreading,blockingqueue,Java,Multithreading,Blockingqueue,在我的应用程序中有两个阶段,一个是下载一些大数据,另一个是操纵数据。 因此,我创建了两个实现runnable的类:ImageDownloader和ImageManipulator,它们共享一个downloadedBlockingQueue: public class ImageDownloader implements Runnable { private ArrayBlockingQueue<ImageBean> downloadedImagesB

在我的应用程序中有两个阶段,一个是下载一些大数据,另一个是操纵数据。 因此,我创建了两个实现runnable的类:ImageDownloader和ImageManipulator,它们共享一个downloadedBlockingQueue:

        public class ImageDownloader implements Runnable {

        private ArrayBlockingQueue<ImageBean> downloadedImagesBlockingQueue;
        private ArrayBlockingQueue<String> imgUrlsBlockingQueue;

        public ImageDownloader(ArrayBlockingQueue<String> imgUrlsBlockingQueue, ArrayBlockingQueue<ImageBean> downloadedImagesBlockingQueue) {

            this.downloadedImagesBlockingQueue = downloadedImagesBlockingQueue;
            this.imgUrlsBlockingQueue = imgUrlsBlockingQueue;

        }

        @Override
        public void run() {
            while (!this.imgUrlsBlockingQueue.isEmpty()) {
                try {
                    String imgUrl = this.imgUrlsBlockingQueue.take();
                    ImageBean imageBean = doYourThing(imgUrl);
                    this.downloadedImagesBlockingQueue.add(imageBean);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

        public class ImageManipulator implements Runnable {

        private ArrayBlockingQueue<ImageBean> downloadedImagesBlockingQueue;
        private AtomicInteger capacity;

        public ImageManipulator(ArrayBlockingQueue<ImageBean> downloadedImagesBlockingQueue,
                                AtomicInteger capacity) {
            this.downloadedImagesBlockingQueue = downloadedImagesBlockingQueue;
            this.capacity = capacity;
        }

        @Override
        public void run() {
            while (capacity.get() > 0) {
                try {
                    ImageBean imageBean = downloadedImagesBlockingQueue.take(); // <- HERE I GET THE DEADLOCK
                    capacity.decrementAndGet();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // ....
            }
        }
    }




    public class Main {
        public static void main(String[] args) {
            String[] imageUrls = new String[]{"url1", "url2"};
            int capacity = imageUrls.length;

            ArrayBlockingQueue<String> imgUrlsBlockingQueue = initImgUrlsBlockingQueue(imageUrls, capacity);
            ArrayBlockingQueue<ImageBean> downloadedImagesBlockingQueue = new ArrayBlockingQueue<>(capacity);

            ExecutorService downloaderExecutor = Executors.newFixedThreadPool(3);
            for (int i = 0; i < 3; i++) {
                Runnable worker = new ImageDownloader(imgUrlsBlockingQueue, downloadedImagesBlockingQueue);
                downloaderExecutor.execute(worker);
            }
            downloaderExecutor.shutdown();

            ExecutorService manipulatorExecutor = Executors.newFixedThreadPool(3);
            AtomicInteger manipulatorCapacity = new AtomicInteger(capacity);

            for (int i = 0; i < 3; i++) {
                Runnable worker = new ImageManipulator(downloadedImagesBlockingQueue, manipulatorCapacity);
                manipulatorExecutor.execute(worker);
            }
            manipulatorExecutor.shutdown();
            while (!downloaderExecutor.isTerminated() && !manipulatorExecutor.isTerminated()) {
            }
        }
    }
公共类ImageDownloader实现可运行{
私有阵列锁定队列下载图像锁定队列;
专用ArrayBlockingQueue imgUrlsBlockingQueue;
公共图像下载程序(ArrayBlockingQueue imgUrlsBlockingQueue,ArrayBlockingQueue downloadedImagesBlockingQueue){
this.downloadeImagesBlockingQueue=downloadeImagesBlockingQueue;
this.imgUrlsBlockingQueue=imgUrlsBlockingQueue;
}
@凌驾
公开募捐{
而(!this.imgUrlsBlockingQueue.isEmpty()){
试一试{
字符串imgUrl=this.imgUrlsBlockingQueue.take();
ImageBean ImageBean=doYourThing(imgUrl);
this.downloadeImagesBlockingQueue.add(imageBean);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
}
公共类ImageManipulator实现可运行{
私有阵列锁定队列下载图像锁定队列;
私有原子能力;
公共图像操纵器(ArrayBlockingQueue下载图像锁定队列,
原子(整数容量){
this.downloadeImagesBlockingQueue=downloadeImagesBlockingQueue;
这个。容量=容量;
}
@凌驾
公开募捐{
while(capacity.get()>0){
试一试{

ImageBean ImageBean=downloadeImagesBlockingQueue.take();//您不需要消费者中的
容量。它现在在多个线程中读取和更新,这会导致同步问题

  • initImgUrlsBlockingQueue
    使用
    容量
    url项目数创建url阻止队列。(对吗?)
  • ImageDownloader
    使用
    imgUrlsBlockingQueue
    并生成图像,它在下载所有URL时终止,或者,如果
    capacity
    表示由于可能出现故障而应下载的图像数,它在添加
    capacity
    图像数时终止
  • ImageDownloader
    终止之前,它会在
    downloadedImagesBlockingQueue
    中添加一个标记,例如,一个空元素,一个静态最终ImageBean
    静态最终ImageBean marker=new ImageBean()
  • 所有
    ImageManipulator
    都使用以下构造来清空队列,当它看到null元素时,它会再次将其添加到队列并终止

    // use identity comparison
    while ((imageBean = downloadedImagesBlockingQueue.take()) != marker) {
       // process image
    }
    downloadedImagesBlockingQueue.add(marker);
    

  • 请注意,
    BlockingQueue
    承诺其方法将其称为原子,但是,如果您首先检查其容量,并根据容量使用一个元素,则操作组将不会是原子的。

    您可以做几件事来防止死锁:

    • 使用具有容量的
      LinkedBlockingQueue
    • 使用
      offer
      添加到不阻塞的队列中
    • 使用
      drainTo
      poll
      从队列中提取未阻塞的项目
    您可能还需要考虑一些技巧:

    • 使用
      线程池

      final ExecutorService ExecutorService=Executors.newFixedThreadPool(4);
    • 如果使用固定大小的
      线程池
      ,则可以在将数据添加到与
      线程池
      大小对应的队列中后添加s,并在
      轮询时检查它
    使用
    线程池
    非常简单:

        final ExecutorService executorService = Executors.newFixedThreadPool(4);
    
        final Future<?> result = executorService.submit(new Runnable() {
            @Override
            public void run() {
    
            }
        });
    
    final ExecutorService ExecutorService=Executors.newFixedThreadPool(4);
    最终的未来结果=executorService.submit(新的Runnable(){
    @凌驾
    公开募捐{
    }
    });
    

    还有一个鲜为人知的
    ExecutorCompletionService
    ,它对整个过程进行了抽象。更多信息。

    您的问题是,您试图使用计数器跟踪队列元素,而不是编写需要原子化的操作。您正在执行检查、取数、减量。这允许队列大小和计数器去同步并且线程会永远阻塞。最好编写一个“可关闭”的同步原语,这样就不必保留关联的计数器。但是,一个快速解决方法是更改它,这样就可以获得并原子地递减计数器:

    while (capacity.getAndDecrement() > 0) {
        try {
            ImageBean imageBean = downloadedImagesBlockingQueue.take();
    
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    

    在这种情况下,如果有3个线程,队列中只剩下一个元素,那么只有一个线程将自动减少计数器,并查看它是否可以在不阻塞的情况下运行。其他两个线程都将看到0或好的,我使用了一些建议的功能,但这是我的完整解决方案,一个不忙着等待和不等待的线程直到下载程序通知它

    public ImageManipulator(LinkedBlockingQueue<ImageBean> downloadedImagesBlockingQueue,
                            LinkedBlockingQueue<ImageBean> manipulatedImagesBlockingQueue,
                            AtomicInteger capacity,
                            ManipulatedData manipulatedData,
                            ReentrantLock downloaderReentrantLock,
                            ReentrantLock manipulatorReentrantLock,
                            Condition downloaderNotFull,
                            Condition manipulatorNotFull) {
    
        this.downloadedImagesBlockingQueue = downloadedImagesBlockingQueue;
        this.manipulatedImagesBlockingQueue = manipulatedImagesBlockingQueue;
        this.capacity = capacity;
        this.downloaderReentrantLock = downloaderReentrantLock;
        this.manipulatorReentrantLock = manipulatorReentrantLock;
        this.downloaderNotFull = downloaderNotFull;
        this.manipulatorNotFull = manipulatorNotFull;
        this.manipulatedData = manipulatedData;
    }
    
    @Override
    public void run() {
        while (capacity.get() > 0) {
            downloaderReentrantLock.lock();
            if (capacity.get() > 0) { //checks if the value is updated.
    
                ImageBean imageBean = downloadedImagesBlockingQueue.poll();
    
                if (imageBean != null) { // will be null if no downloader finished is work (successfully downloaded or not)
    
                    capacity.decrementAndGet();
                    if (capacity.get() == 0) { //signal all the manipulators to wake up and stop waiting for downloaded images.
                        downloaderNotFull.signalAll();
                    }
                    downloaderReentrantLock.unlock();
    
                    if (imageBean.getOriginalImage() != null) { // the downloader will set it null iff it failes to download it.
    
                         // business logic
                    }
    
                    manipulatedImagesBlockingQueue.add(imageBean);
    
                    signalAllPersisters(); // signal the persisters (which has the same lock/unlock as this manipulator.
    
                } else {
                    try {
                        downloaderNotFull.await(); //manipulator will wait for downloaded image - downloader will signalAllManipulators (same as signalAllPersisters() here) when an imageBean will be inserted to queue.
                        downloaderReentrantLock.unlock();
                    } catch (InterruptedException e) {
                        logger.log(Level.ERROR, e.getMessage(), e);
                    }
                }
            }
        }
    
        logger.log(Level.INFO, "Manipulator: " + Thread.currentThread().getId() + "  Ended Gracefully");
    }
    
    private void signalAllPersisters() {
        manipulatorReentrantLock.lock();
        manipulatorNotFull.signalAll();
        manipulatorReentrantLock.unlock();
    }
    
    公共图像操纵器(LinkedBlockingQueue下载图像锁定队列,
    LinkedBlockingQueue操纵ImagesBlockingQueue,
    原子整数容量,
    操纵数据操纵数据,
    ReentrantLock下载程序ReentrantLock,
    可重入锁定操纵器可重入锁定,
    条件下载未满,
    条件(或未满){
    this.downloadeImagesBlockingQueue=downloadeImagesBlockingQueue;
    this.manipedimagesblockingqueue=manipedimagesblockingqueue;
    这个。容量=容量;
    this.downloaderReentrantLock=downloaderReentrantLock;
    this.manufactorreentrantlock=manufactorreentrantlock;
    this.downloaderNotFull=downloaderNotFull;
    this.manufactornotfull=manipul