第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時(shí)綁定郵箱和手機(jī)立即綁定

使用Thread Pool不當(dāng)引發(fā)的死鎖

標(biāo)簽:
Java

简介

多线程锁定同一资源会造成死锁

线程池中的任务使用当前线程池也可能出现死锁

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();

        }

    }

}

可以看到,有两种伐木工:先戴好安全帽然后再拿电锯的,另一种则相反。谨慎派(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();

    }

}

现在,让我们来看有趣的部分。如果我们只创建谨慎派伐木工(careful Lumberjacks),应用程序几乎瞬间运行完成,举个例子:

ExecutorService pool = Executors.newFixedThreadPool(10);

Logging logging = new Logging(new Names());

try (Forest forest = new Forest(pool, logging)) {

    forest.cutTrees(10000, 10, 0);

} catch (TimeoutException e) {

    log.warn("Working for too long", e);

}



作者:java菜
链接:https://www.jianshu.com/p/616909841551


點(diǎn)擊查看更多內(nèi)容
TA 點(diǎn)贊

若覺得本文不錯(cuò),就分享一下吧!

評論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學(xué)習(xí),寫下你的評論
感謝您的支持,我會繼續(xù)努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊有機(jī)會得

100積分直接送

付費(fèi)專欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號

舉報(bào)

0/150
提交
取消