轮询锁使用时遇到的问题与解决方案!

开发 前端
轮询锁在使用的过程中,如果使用不当会带来新的严重问题,所以本篇我们就来了解一下这些问题,以及相应的解决方案。

[[420554]]

作者 | 王磊

来源 | Java中文社群(ID:javacn666)

转载请联系授权(微信ID:GG_Stone

当我们遇到死锁之后,除了可以手动重启程序解决之外,还可以考虑是使用顺序锁和轮询锁,这部分的内容可以参考我的上一篇文章,这里就不再赘述了。然而,轮询锁在使用的过程中,如果使用不当会带来新的严重问题,所以本篇我们就来了解一下这些问题,以及相应的解决方案。

问题演示

当我们没有使用轮询锁之前,可能会出现这样的问题:

import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 
 
publicclass DeadLockByReentrantLock { 
    public static void main(String[] args) { 
        Lock lockA = new ReentrantLock(); // 创建锁 A 
        Lock lockB = new ReentrantLock(); // 创建锁 B 
 
        // 创建线程 1 
        Thread t1 = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                lockA.lock(); // 加锁 
                System.out.println("线程 1:获取到锁 A!"); 
                try { 
                    Thread.sleep(1000); 
                    System.out.println("线程 1:等待获取 B..."); 
                    lockB.lock(); // 加锁 
                    try { 
                        System.out.println("线程 1:获取到锁 B!"); 
                    } finally { 
                        lockA.unlock(); // 释放锁 
                    } 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } finally { 
                    lockA.unlock(); // 释放锁 
                } 
            } 
        }); 
        t1.start(); // 运行线程 
 
        // 创建线程 2 
        Thread t2 = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                lockB.lock(); // 加锁 
                System.out.println("线程 2:获取到锁 B!"); 
                try { 
                    Thread.sleep(1000); 
                    System.out.println("线程 2:等待获取 A..."); 
                    lockA.lock(); // 加锁 
                    try { 
                        System.out.println("线程 2:获取到锁 A!"); 
                    } finally { 
                        lockA.unlock(); // 释放锁 
                    } 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } finally { 
                    lockB.unlock(); // 释放锁 
                } 
            } 
        }); 
        t2.start(); // 运行线程 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.

以上代码的执行结果如下:

从上述结果可以看出,此时程序中出现了线程相互等待,并尝试获取对方(锁)资源的情况,这就是典型的死锁问题了。

简易版轮询锁

当出现死锁问题之后,我们就可以使用轮询锁来解决它了,它的实现思路是通过轮询的方式来获取多个锁,如果中途有任意一个锁获取失败,则执行回退操作,释放当前线程拥有的所有锁,等待下一次重新执行,这样就可以避免多个线程同时拥有并霸占锁资源了,从而直接解决了死锁的问题,简易版的轮询锁实现如下:

import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 
 
publicclass SolveDeadLockExample2 { 
    public static void main(String[] args) { 
        Lock lockA = new ReentrantLock(); // 创建锁 A 
        Lock lockB = new ReentrantLock(); // 创建锁 B 
 
        // 创建线程 1(使用轮询锁) 
        Thread t1 = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                // 调用轮询锁 
                pollingLock(lockA, lockB); 
            } 
        }); 
        t1.start(); // 运行线程 
 
        // 创建线程 2 
        Thread t2 = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                lockB.lock(); // 加锁 
                System.out.println("线程 2:获取到锁 B!"); 
                try { 
                    Thread.sleep(1000); 
                    System.out.println("线程 2:等待获取 A..."); 
                    lockA.lock(); // 加锁 
                    try { 
                        System.out.println("线程 2:获取到锁 A!"); 
                    } finally { 
                        lockA.unlock(); // 释放锁 
                    } 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } finally { 
                    lockB.unlock(); // 释放锁 
                } 
            } 
        }); 
        t2.start(); // 运行线程 
    } 
 
    /** 
     * 轮询锁 
     */ 
    private static void pollingLock(Lock lockA, Lock lockB) { 
        // 轮询锁 
        while (true) { 
            if (lockA.tryLock()) { // 尝试获取锁 
                System.out.println("线程 1:获取到锁 A!"); 
                try { 
                    Thread.sleep(1000); 
                    System.out.println("线程 1:等待获取 B..."); 
                    if (lockB.tryLock()) { // 尝试获取锁 
                        try { 
                            System.out.println("线程 1:获取到锁 B!"); 
                        } finally { 
                            lockB.unlock(); // 释放锁 
                            System.out.println("线程 1:释放锁 B."); 
                            break; 
                        } 
                    } 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } finally { 
                    lockA.unlock(); // 释放锁 
                    System.out.println("线程 1:释放锁 A."); 
                } 
            } 
            // 等待一秒再继续执行 
            try { 
                Thread.sleep(1000); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.

以上代码的执行结果如下:

从上述结果可以看出,当我们在程序中使用轮询锁之后就不会出现死锁的问题了,但以上轮询锁也并不是完美无缺的,下面我们来看看这个轮询锁会有什么样的问题?

问题1:死循环

以上简易版的轮询锁,如果遇到有一个线程一直霸占或者长时间霸占锁资源的情况,就会导致这个轮询锁进入死循环的状态,它会尝试一直获取锁资源,这样就会造成新的问题,带来不必要的性能开销,具体示例如下。

反例

import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 
 
publicclass SolveDeadLockExample { 
 
    public static void main(String[] args) { 
        Lock lockA = new ReentrantLock(); // 创建锁 A 
        Lock lockB = new ReentrantLock(); // 创建锁 B 
 
        // 创建线程 1(使用轮询锁) 
        Thread t1 = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                // 调用轮询锁 
                pollingLock(lockA, lockB); 
            } 
        }); 
        t1.start(); // 运行线程 
 
        // 创建线程 2 
        Thread t2 = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                lockB.lock(); // 加锁 
                System.out.println("线程 2:获取到锁 B!"); 
                try { 
                    Thread.sleep(1000); 
                    System.out.println("线程 2:等待获取 A..."); 
                    lockA.lock(); // 加锁 
                    try { 
                        System.out.println("线程 2:获取到锁 A!"); 
                    } finally { 
                        lockA.unlock(); // 释放锁 
                    } 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } finally { 
                    // 如果此处代码未执行,线程 2 一直未释放锁资源 
                    // lockB.unlock();  
                } 
            } 
        }); 
        t2.start(); // 运行线程 
    } 
 
    /** 
     * 轮询锁 
     */ 
    public static void pollingLock(Lock lockA, Lock lockB) { 
        while (true) { 
            if (lockA.tryLock()) { // 尝试获取锁 
                System.out.println("线程 1:获取到锁 A!"); 
                try { 
                    Thread.sleep(1000); 
                    System.out.println("线程 1:等待获取 B..."); 
                    if (lockB.tryLock()) { // 尝试获取锁 
                        try { 
                            System.out.println("线程 1:获取到锁 B!"); 
                        } finally { 
                            lockB.unlock(); // 释放锁 
                            System.out.println("线程 1:释放锁 B."); 
                            break; 
                        } 
                    } 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } finally { 
                    lockA.unlock(); // 释放锁 
                    System.out.println("线程 1:释放锁 A."); 
                } 
            } 
            // 等待一秒再继续执行 
            try { 
                Thread.sleep(1000); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.

以上代码的执行结果如下:

从上述结果可以看出,线程 1 轮询锁进入了死循环的状态。

优化版

针对以上死循环的情况,我们可以改进的思路有以下两种:

  1. 添加最大次数限制:如果经过了 n 次尝试获取锁之后,还未获取到锁,则认为获取锁失败,执行失败策略之后终止轮询(失败策略可以是记录日志或其他操作);
  2. 添加最大时长限制:如果经过了 n 秒尝试获取锁之后,还未获取到锁,则认为获取锁失败,执行失败策略之后终止轮询。

以上策略任选其一就可以解决死循环的问题,出于实现成本的考虑,我们可以采用轮询最大次数的方式来改进轮询锁,具体实现代码如下:

import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 
 
publicclass SolveDeadLockExample { 
 
    public static void main(String[] args) { 
        Lock lockA = new ReentrantLock(); // 创建锁 A 
        Lock lockB = new ReentrantLock(); // 创建锁 B 
 
        // 创建线程 1(使用轮询锁) 
        Thread t1 = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                // 调用轮询锁 
                pollingLock(lockA, lockB, 3); 
            } 
        }); 
        t1.start(); // 运行线程 
 
        // 创建线程 2 
        Thread t2 = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                lockB.lock(); // 加锁 
                System.out.println("线程 2:获取到锁 B!"); 
                try { 
                    Thread.sleep(1000); 
                    System.out.println("线程 2:等待获取 A..."); 
                    lockA.lock(); // 加锁 
                    try { 
                        System.out.println("线程 2:获取到锁 A!"); 
                    } finally { 
                        lockA.unlock(); // 释放锁 
                    } 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } finally { 
                    // 线程 2 忘记释放锁资源 
                    // lockB.unlock(); // 释放锁 
                } 
            } 
        }); 
        t2.start(); // 运行线程 
    } 
 
    /** 
     * 轮询锁 
     * 
     * maxCount:最大轮询次数 
     */ 
    public static void pollingLock(Lock lockA, Lock lockB, int maxCount) { 
        // 轮询次数计数器 
        int count = 0; 
        while (true) { 
            if (lockA.tryLock()) { // 尝试获取锁 
                System.out.println("线程 1:获取到锁 A!"); 
                try { 
                    Thread.sleep(1000); 
                    System.out.println("线程 1:等待获取 B..."); 
                    if (lockB.tryLock()) { // 尝试获取锁 
                        try { 
                            System.out.println("线程 1:获取到锁 B!"); 
                        } finally { 
                            lockB.unlock(); // 释放锁 
                            System.out.println("线程 1:释放锁 B."); 
                            break; 
                        } 
                    } 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } finally { 
                    lockA.unlock(); // 释放锁 
                    System.out.println("线程 1:释放锁 A."); 
                } 
            } 
 
            // 判断是否已经超过最大次数限制 
            if (count++ > maxCount) { 
                // 终止循环 
                System.out.println("轮询锁获取失败,记录日志或执行其他失败策略"); 
                return
            } 
 
            // 等待一秒再继续尝试获取锁 
            try { 
                Thread.sleep(1000); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.

以上代码的执行结果如下:

从以上结果可以看出,当我们改进之后,轮询锁就不会出现死循环的问题了,它会尝试一定次数之后终止执行。

问题2:线程饿死

我们以上的轮询锁的轮询等待时间是固定时间,如下代码所示:

// 等待 1s 再尝试获取(轮询)锁 
try { 
    Thread.sleep(1000); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

这样在特殊情况下会造成线程饿死的问题,也就是轮询锁一直获取不到锁的问题,比如以下示例。

反例

import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 
 
publicclass SolveDeadLockExample { 
 
    public static void main(String[] args) { 
        Lock lockA = new ReentrantLock(); // 创建锁 A 
        Lock lockB = new ReentrantLock(); // 创建锁 B 
 
        // 创建线程 1(使用轮询锁) 
        Thread t1 = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                // 调用轮询锁 
                pollingLock(lockA, lockB, 3); 
            } 
        }); 
        t1.start(); // 运行线程 
 
        // 创建线程 2 
        Thread t2 = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                while (true) { 
                    lockB.lock(); // 加锁 
                    System.out.println("线程 2:获取到锁 B!"); 
                    try { 
                        System.out.println("线程 2:等待获取 A..."); 
                        lockA.lock(); // 加锁 
                        try { 
                            System.out.println("线程 2:获取到锁 A!"); 
                        } finally { 
                            lockA.unlock(); // 释放锁 
                        } 
                    } finally { 
                        lockB.unlock(); // 释放锁 
                    } 
                    // 等待一秒之后继续执行 
                    try { 
                        Thread.sleep(1000); 
                    } catch (InterruptedException e) { 
                        e.printStackTrace(); 
                    } 
                } 
            } 
        }); 
        t2.start(); // 运行线程 
    } 
 
    /** 
     * 轮询锁 
     */ 
    public static void pollingLock(Lock lockA, Lock lockB, int maxCount) { 
        // 循环次数计数器 
        int count = 0; 
        while (true) { 
            if (lockA.tryLock()) { // 尝试获取锁 
                System.out.println("线程 1:获取到锁 A!"); 
                try { 
                    Thread.sleep(100); // 等待 0.1s(获取锁需要的时间) 
                    System.out.println("线程 1:等待获取 B..."); 
                    if (lockB.tryLock()) { // 尝试获取锁 
                        try { 
                            System.out.println("线程 1:获取到锁 B!"); 
                        } finally { 
                            lockB.unlock(); // 释放锁 
                            System.out.println("线程 1:释放锁 B."); 
                            break; 
                        } 
                    } 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } finally { 
                    lockA.unlock(); // 释放锁 
                    System.out.println("线程 1:释放锁 A."); 
                } 
            } 
 
            // 判断是否已经超过最大次数限制 
            if (count++ > maxCount) { 
                // 终止循环 
                System.out.println("轮询锁获取失败,记录日志或执行其他失败策略"); 
                return
            } 
 
            // 等待一秒再继续尝试获取锁 
            try { 
                Thread.sleep(1000); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.

以上代码的执行结果如下:

从上述结果可以看出,线程 1(轮询锁)一直未成功获取到锁,造成这种结果的原因是:线程 1 每次轮询的等待时间为固定的 1s,而线程 2 也是相同的频率,每 1s 获取一次锁,这样就会导致线程 2 会一直先成功获取到锁,而线程 1 则会一直处于“饿死”的情况,执行流程如下图所示:

优化版

接下来,我们可以将轮询锁的固定等待时间,改进为固定时间 + 随机时间的方式,这样就可以避免因为获取锁的频率一致,而造成轮询锁“饿死”的问题了,具体实现代码如下:

import java.util.Random; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 
 
publicclass SolveDeadLockExample { 
    privatestatic Random rdm = new Random(); 
 
    public static void main(String[] args) { 
        Lock lockA = new ReentrantLock(); // 创建锁 A 
        Lock lockB = new ReentrantLock(); // 创建锁 B 
 
        // 创建线程 1(使用轮询锁) 
        Thread t1 = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                // 调用轮询锁 
                pollingLock(lockA, lockB, 3); 
            } 
        }); 
        t1.start(); // 运行线程 
 
        // 创建线程 2 
        Thread t2 = new Thread(new Runnable() { 
            @Override 
            public void run() { 
                while (true) { 
                    lockB.lock(); // 加锁 
                    System.out.println("线程 2:获取到锁 B!"); 
                    try { 
                        System.out.println("线程 2:等待获取 A..."); 
                        lockA.lock(); // 加锁 
                        try { 
                            System.out.println("线程 2:获取到锁 A!"); 
                        } finally { 
                            lockA.unlock(); // 释放锁 
                        } 
                    } finally { 
                        lockB.unlock(); // 释放锁 
                    } 
                    // 等待一秒之后继续执行 
                    try { 
                        Thread.sleep(1000); 
                    } catch (InterruptedException e) { 
                        e.printStackTrace(); 
                    } 
                } 
            } 
        }); 
        t2.start(); // 运行线程 
    } 
 
    /** 
     * 轮询锁 
     */ 
    public static void pollingLock(Lock lockA, Lock lockB, int maxCount) { 
        // 循环次数计数器 
        int count = 0; 
        while (true) { 
            if (lockA.tryLock()) { // 尝试获取锁 
                System.out.println("线程 1:获取到锁 A!"); 
                try { 
                    Thread.sleep(100); // 等待 0.1s(获取锁需要的时间) 
                    System.out.println("线程 1:等待获取 B..."); 
                    if (lockB.tryLock()) { // 尝试获取锁 
                        try { 
                            System.out.println("线程 1:获取到锁 B!"); 
                        } finally { 
                            lockB.unlock(); // 释放锁 
                            System.out.println("线程 1:释放锁 B."); 
                            break; 
                        } 
                    } 
                } catch (InterruptedException e) { 
                    e.printStackTrace(); 
                } finally { 
                    lockA.unlock(); // 释放锁 
                    System.out.println("线程 1:释放锁 A."); 
                } 
            } 
 
            // 判断是否已经超过最大次数限制 
            if (count++ > maxCount) { 
                // 终止循环 
                System.out.println("轮询锁获取失败,记录日志或执行其他失败策略"); 
                return
            } 
 
            // 等待一定时间(固定时间 + 随机时间)之后再继续尝试获取锁 
            try { 
                Thread.sleep(300 + rdm.nextInt(8) * 100); // 固定时间 + 随机时间 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
        } 
    } 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.

以上代码的执行结果如下:

从上述结果可以看出,线程 1(轮询锁)加入随机等待时间之后就不会出现线程饿死的问题了。

总结

本文我们介绍了轮询锁的用途,用于解决死锁问题,但简易版的轮询锁在某些情况下会造成死循环和线程饿死的问题,因此我们对轮询锁进行了优化,给轮询锁加入了最大轮询次数,以及随机轮询等待时间,这样就可以解决因为引入轮询锁而造成的新问题了,这样就可以愉快的使用它来解决死锁的问题了。

 

责任编辑:姜华 来源: Java中文社群
相关推荐

2017-08-03 09:37:35

SparkStreamKafkaDirect

2017-08-01 05:44:10

Dockerweave虚拟机

2017-06-23 11:20:00

DockerWeave内核

2015-05-12 16:31:22

Elasticsear开源分布式搜索引擎

2024-11-08 13:47:35

中文乱码配置

2010-05-17 09:49:46

MySQL中文问题

2011-03-02 14:56:56

FileZilla425问题

2024-12-02 01:16:53

2010-05-12 14:18:58

Linux引导

2024-05-23 07:59:42

RedisKey性能

2022-03-31 20:20:46

大数据挑战解决方案

2025-02-04 17:40:44

2010-07-13 10:56:43

Perl print

2013-04-02 09:25:20

PaaS 应用可移植性PaaS提供商平台即服务

2009-08-03 18:06:28

JS性能问题

2023-10-16 16:08:42

工业 4.0物联网边缘计算

2022-03-31 10:25:20

物联网工业 4.0大数据分析

2010-05-31 12:38:48

Nagios中文

2021-01-12 11:02:56

云计算云存储技术云开发

2021-08-05 08:32:27

React开发项目
点赞
收藏

51CTO技术栈公众号