关于java:Java并发编程阶段性总结活跃性问题

2次阅读

共计 1689 个字符,预计需要花费 5 分钟才能阅读完成。

并发编程有 3 道关卡,别离是:安全性问题、活跃性问题、性能问题,如果三关全过,也就把握并发编程这门高阶技能。

明天,咱们就来过第二关:解决活跃性问题。

活跃性问题

所谓活跃性问题,是指程序没法执行上来。

比如说,公司有一个转账的业务,你曾经实现了线程平安,解决了安全性问题,并发再高也不出错。那这样是不是齐全没问题了呢?

当然不是,程序还会呈现 活跃性问题,包含:死锁、饥饿、活锁。

其中,活锁是难度最低的一个问题,解决起来非常容易。而且,即便你不解决,活锁也很可能主动解开,齐全不必放心。当然,如果你对活锁感兴趣,能够看这篇文章:Java 并发编程 - 活锁:它是那种很少见,又没啥危险的 Bug,这里就不多说了,咱们得抓重点。

死锁、饥饿是活跃性问题的要害,只有有方法解决这两个问题,就能买通第二关了。

死锁

死锁,是指两个以上的线程在执行的时候,因为竞争资源造成相互期待,从而进入“永恒”阻塞的状态。这听起来有点拗口,咱们还是间接看代码:

class Account {
    // 余额
    private Integer balance;

    // 转账
    void transfer(Account target, Integer amt) {synchronized (this) {synchronized (target) {if (this.balance > amt) {
                    this.balance -= amt;
                    target.balance += amt;
                }
            }
        }
    }
}

下面是一段转账的代码,假如当初同时有两笔交易,账户 A 账户 B 账户 B 账户 A ,这就有了线程一、线程二。那么,问题来了,线程一锁定了 账户 A ,线程二锁定了 账户 B ,它们都须要对方的资源能力执行,可资源曾经被锁定了,只有执行完程序能力开释。

这样一来,线程一、线程二都只能死死等着,永远没法执行。这就是经典的死锁问题,你能够看上面的图:

在这副图中,两个线程造成一个完满的闭环,基本没法进来。你能够看下这篇文章:Java 并发编程 - 死锁(上),外面从头到尾,写了死锁产生的过程。

既然如此,死锁问题该怎么解决呢?除了重启利用外,死锁没法解决,惟一可行的方法是:躲避死锁,不让死锁呈现。至于怎么躲避,你能够看这篇文章:Java 并发编程 - 死锁(下),外面有躲避死锁的思路。

饥饿

饥饿,就是线程拿不到须要的资源,始终没法执行。比如说,上面这段代码:

class Account {
    // 余额
    private Integer balance;

    // 转账
    void transfer(Account target, Integer amt) {synchronized (Account.class) {
            // 本零碎操作:批改余额,破费 0.01 秒
            if (this.balance > amt) {
                this.balance -= amt;
                target.balance += amt;
            }
            // 调用内部零碎:转账,破费 5 秒
            payService.transfer(this, target, amt);
        }
    }
}

这是一段转账的代码,咱们如果想要执行转账,那么必须锁定 Account.class。然而,Account.class 由 Java 虚拟机创立,只有一个。这就意味着,所有的转账交易都是串行的,只能一笔一笔的解决,效率极低。

此外,payService.transfer(this, target, amt) 这行代码切实是浪费时间,无论电脑配置多好,速度也齐全没法晋升。

最致命的是,实现工夫没法确定。synchronized 是非偏心锁,解决程序是随机的,可能等待时间短的交易反而先解决,等待时间长的始终不解决。

这就导致,一旦业务量大了,公司的投诉电话很可能被打爆。不过,侥幸的是,尽管转账很慢,但程序自身没有问题,只是资源太少,始终没机会运行。

那么,该怎么解决饥饿问题呢?

你能够看看这篇文章:Java 并发编程 - 饥饿,外面讲到了缓解饥饿的三个思路。

写在最初

并发编程有 3 个关卡:安全性问题、活跃性问题、性能问题,咱们明天过的是第二关:活跃性问题。

从这一关开始,咱们要特地留神:死锁、饥饿。你能够回顾一下这些文章:Java 并发编程 - 死锁(上)、Java 并发编程 - 死锁(下)、Java 并发编程 - 饥饿。

正文完
 0