欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识

logging)) { f 图纸加密 orest.cutTrees(10000

点击: 次  来源:劳务派遣管理系统 时间:2018-10-24

本文由 ImportNew - 一杯哈希不加盐 翻译自 dzone。接待插手翻译小组。转载请见文末要求。

简介

  • 多线程锁定同一资源会造成死锁
  • 线程池中的任务利用当前线程池也大概呈现死锁
  • RxJava 或 Reactor 等现代风行库也大概呈现死锁
  • 死锁是两个或多个线程相互期待对方所拥有的资源的景象。举个例子,线程 A 期待 lock1,lock1 当前由线程 B 锁住,然而线程 B 也在期待由线程 A 锁住的 lock2。最坏环境下,应用措施将无限期冻结。让我给你看个具编制子。假设这里有个 Lumberjack(伐木匠) 类,包括了两个装备的锁:

    import com.google.common.collect.ImmutableList;
    import lombok.RequiredArgsConstructor;
    import java.util.concurrent.locks.Lock;
    @RequiredArgsConstructor
    class Lumberjack {
        private final String name;
        private final Lock accessoryOne;
        private final Lock accessoryTwo;
        void cut(Runnable work) {
            try {
                accessoryOne.lock();
                try {
                    accessoryTwo.lock();
                    work.run();
                } finally {
                    accessoryTwo.unlock();
                }
            } finally {
                accessoryOne.unlock();
            }
        }
    }

    每个 Lumberjack(伐木匠)需要两件装备:helmet(安详帽) 和 chainsaw(电锯)。在他开始事情前,劳务派遣管理系统,他必需拥有全部两件装备。我们通过如下方法建设伐木匠们:

    import lombok.RequiredArgsConstructor;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    @RequiredArgsConstructor
    class Logging {
        private final Names names;
        private final Lock helmet = new ReentrantLock();
        private final Lock chainsaw = new ReentrantLock();
        Lumberjack careful() {
            return new Lumberjack(names.getRandomName(), helmet, chainsaw);
        }
        Lumberjack yolo() {
            return new Lumberjack(names.getRandomName(), chainsaw, helmet);
        }
    }

    可以看到,有两种伐木匠:先戴好安详帽然后再拿电锯的,另一种则相反。审慎派(careful())伐木匠先戴好安详帽,然后去拿电锯。狂野派伐木匠(yolo())先拿电锯,然后找安详帽。让我们并产生成一些伐木匠:

    private List<Lumberjack> generate(int count, Supplier<Lumberjack> factory) {
        return IntStream
                .range(0, count)
                .mapToObj(x -> factory.get())
                .collect(toList());
    }

    generate()要领可以建设指定范例伐木匠的荟萃。我们来生成一些审慎派伐木匠和狂野派伐木匠。

    private final Logging logging;
    //...
    List<Lumberjack> lumberjacks = new CopyOnWriteArrayList<>();
    lumberjacks.addAll(generate(carefulLumberjacks, logging::careful));
    lumberjacks.addAll(generate(yoloLumberjacks, logging::yolo));

    最后,我们让这些伐木匠开始事情:

    IntStream
            .range(0, howManyTrees)
            .forEach(x -> {
                Lumberjack roundRobinJack = lumberjacks.get(x % lumberjacks.size());
                pool.submit(() -> {
                    log.debug("{} cuts down tree, {} left", roundRobinJack, latch.getCount());
                    roundRobinJack.cut(/* ... */);
                });
            });

    这个轮回让所有伐木匠一个接一个(轮询方法)去砍树。实质上,我们向线程池(ExecutorService)提交了和树木数量(howManyTrees)沟通个数的任务,并利用 CountDownLatch 来记录事情是否完成。

    CountDownLatch latch = new CountDownLatch(howManyTrees);
    IntStream
            .range(0, howManyTrees)
            .forEach(x -> {
                pool.submit(() -> {
                    //...
                    roundRobinJack.cut(latch::countDown);
                });
            });
    if (!latch.await(10, TimeUnit.SECONDS)) {
        throw new TimeoutException("Cutting forest for too long");
    }

    其实想法很简朴。我们让多个伐木匠(Lumberjacks)通过多线程方法去竞争一个安详帽和一把电锯。完整代码如下:

    import lombok.RequiredArgsConstructor;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.TimeoutException;
    import java.util.function.Supplier;
    import java.util.stream.Collectors;
    import java.util.stream.IntStream;
    @RequiredArgsConstructor
    class Forest implements AutoCloseable {
        private static final Logger log = LoggerFactory.getLogger(Forest.class);
        private final ExecutorService pool;
        private final Logging logging;
        void cutTrees(int howManyTrees, int carefulLumberjacks, int yoloLumberjacks) throws InterruptedException, TimeoutException {
            CountDownLatch latch = new CountDownLatch(howManyTrees);
            List<Lumberjack> lumberjacks = new ArrayList<>();
            lumberjacks.addAll(generate(carefulLumberjacks, logging::careful));
            lumberjacks.addAll(generate(yoloLumberjacks, logging::yolo));
            IntStream
                    .range(0, howManyTrees)
                    .forEach(x -> {
                        Lumberjack roundRobinJack = lumberjacks.get(x % lumberjacks.size());
                        pool.submit(() -> {
                            log.debug("{} cuts down tree, {} left", roundRobinJack, latch.getCount());
                            roundRobinJack.cut(latch::countDown);
                        });
                    });
            if (!latch.await(10, TimeUnit.SECONDS)) {
                throw new TimeoutException("Cutting forest for too long");
            }
            log.debug("Cut all trees");
        }
        private List<Lumberjack> generate(int count, Supplier<Lumberjack> factory) {
            return IntStream
                    .range(0, count)
                    .mapToObj(x -> factory.get())
                    .collect(Collectors.toList());
        }
        @Override
        public void close() {
            pool.shutdownNow();
        }
    }