Skip to main content

锁优化

huhxAbout 3 minjavaConcurrency

在实际的应用中,如果能够在代码的应用层面上进行合理的锁优化,也是会提升系统性能的。这里我们就展开讲讲锁的优化思路。

减少锁持有时间

减少锁的持有时间,其实就是移出没有必要加锁的操作。想想看如果每个人(线程)占了餐馆的位置,并在上面吃饭、打游戏(费时操作),如果是就餐高峰期。每个人占着位置1个多小时,那么就会造成其他很多人没办法就餐。模拟程序如下

Person
class Person {
    void action() throws InterruptedException {
        synchronized (Person.class) {
            eat();
            playGame();
        }
    }

    void eat() throws InterruptedException {
        TimeUnit.SECONDS.sleep(1);
        System.out.println(Thread.currentThread().getName() + " finish eating, time: " + LocalDateTime.now());
    }

    void playGame() throws InterruptedException {
        TimeUnit.SECONDS.sleep(10);
        System.out.println(Thread.currentThread().getName() + " finish gaming, time: " + LocalDateTime.now());
    }
}

每个人占着位子,需要完成吃饭和打完游戏才离开:用时55秒

Start: 2023-09-12T18:51:36.788911
Thread-0 finish eating, time: 2023-09-12T18:51:37.791840
Thread-0 finish gaming, time: 2023-09-12T18:51:47.808546
Thread-3 finish eating, time: 2023-09-12T18:51:48.813600
Thread-3 finish gaming, time: 2023-09-12T18:51:58.815262
Thread-2 finish eating, time: 2023-09-12T18:51:59.815981
Thread-2 finish gaming, time: 2023-09-12T18:52:09.818383
Thread-4 finish eating, time: 2023-09-12T18:52:10.822304
Thread-4 finish gaming, time: 2023-09-12T18:52:20.825164
Thread-1 finish eating, time: 2023-09-12T18:52:21.826791
Thread-1 finish gaming, time: 2023-09-12T18:52:31.832319
End: 2023-09-12T18:52:31.832695

如果修改上述Person类的action方法如下:

void action() throws InterruptedException {
    synchronized (Person.class) {
        eat();
    }
    playGame();
}

真实的业务场景,就是你吃完饭就快些离开释放位子,打游戏不用占着位子: 用时15秒

Start: 2023-09-12T18:55:43.016838
Thread-0 finish eating, time: 2023-09-12T18:55:44.019018
Thread-1 finish eating, time: 2023-09-12T18:55:45.029491
Thread-2 finish eating, time: 2023-09-12T18:55:46.030756
Thread-3 finish eating, time: 2023-09-12T18:55:47.032526
Thread-4 finish eating, time: 2023-09-12T18:55:48.036353
Thread-0 finish gaming, time: 2023-09-12T18:55:54.028820
Thread-1 finish gaming, time: 2023-09-12T18:55:55.026498
Thread-2 finish gaming, time: 2023-09-12T18:55:56.029223
Thread-3 finish gaming, time: 2023-09-12T18:55:57.030282
Thread-4 finish gaming, time: 2023-09-12T18:55:58.037243
End: 2023-09-12T18:55:58.037563

减少锁粒度

锁分离

锁粗化

通常情况下,为了保证多线程的有效并发,会要求每个线程持有锁的时间尽量的短。即在使用完公共资源后,应该立即释放锁。只有这样,等待这个锁的其他线程才能尽早地获得资源执行任务。但是如果对同一个锁不停地进行请求、同步和释放,加上任务运行时间较短,这样消耗系统宝贵的资源,反而不利于性能。

优化前
public class Test1 {
    private final static int concurrency = 100;
    private final static int times = 100000;
    private static volatile int count = 0;

    public static void main(String[] args) throws InterruptedException {
        var threads = new Thread[concurrency];
        for (int i = 0; i < concurrency; i++) {
            threads[i] = new Thread(() -> {
                for (int j = 0; j < times; j++) {
                    synchronized (IncrementMain.class) {
                        count++;
                    }
                }
            });
        }

        long start = System.currentTimeMillis();

        for (Thread thread : threads) thread.start();
        for (Thread thread : threads) thread.join();

        long end = System.currentTimeMillis();

        System.out.printf("result: %d,  time: %d\n", count, end - start);
    }
}

优化前618毫秒,优化后72毫秒。而且随着times增长,这个差距会越来越大。

Info

对于大量出现的短时任务,可以考虑采用锁粗化来进行性能优化。

FAQ

总结

参考