实战Java高并发程序设计(四、锁的优化及注意事项)

在多核时代,使用多线程可以明显地提升系统的性能。但事实上,使用多线程会额外增加系统的开销。对于单任务或单线程的应用来说,其主要资源消耗在任务本身。对于多线程来说,系统除了处理功能需求外,还需要维护多线程环境特有的信息,如线程本身的元数据,线程的调度,线程上下文的切换等。

4.1有助于提高锁性能的建议

4.1.1减少锁持有的时间

如果线程持有锁的时间越长,锁的竞争程度越激烈。

4.1.2减少锁粒度

锁粒度:假如一个线程任务是在家里上厕所,家就是一个线程,卫生间锁门就是加锁。如果马桶,浴缸,洗漱台都是隔开相对独立的,实际上卫生间可以同时给三个人使用,那么再细化锁粒度,就可以对马桶,浴缸,洗漱台分别加锁。

但是当想要获取全局信息时,需要获取所有段的锁才能顺利实施。所以减少锁粒度要慎重。

4.1.3读写分离锁来替换独占锁

在读多写少的场合,使用读写锁可以有效提升系统的并发能力。

4.1.4锁分离

依据应用程序的功能特点,使用类似的分离思想,对独占锁进行分离。

4.2ThreadLocal

ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。举个例子,我出门需要先坐公交再做地铁,这里的坐公交和坐地铁就好比是同一个线程内的两个函数,我就是一个线程,我要完成这两个函数都需要同一个东西:公交卡(北京公交和地铁都使用公交卡),那么我为了不向这两个函数都传递公交卡这个变量(相当于不是一直带着公交卡上路),我可以这么做:将公交卡事先交给一个机构,当我需要刷卡的时候再向这个机构要公交卡(当然每次拿的都是同一张公交卡)。这样就能达到只要是我(同一个线程)需要公交卡,何时何地都能向这个机构要的目的。

举例:有5个线程,这5个线程都有一个值value,初始值为0,线程运行时用一个循环往value值相加数字。

public class Test {
    private static final ThreadLocal<Integer> value = new ThreadLocal<Integer>() {
//        初始化
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };

    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            new Thread(new MyThread(i)).start();
        }
    }

    static class MyThread implements Runnable {
        private int index;

        public MyThread(int index) {
            this.index = index;
        }

        @Override
        public void run() {
            System.out.println("线程" + index + "的初始value:" + value.get());
            for (int i = 0; i < 10; i++) {
                value.set(value.get() + i);
            }
            System.out.println("线程" + index + "的累加value:" + value.get());
        }
    }
}

5个线程之间互不影响。

4.3无锁

后续补充

猜你喜欢

转载自blog.csdn.net/qq_33283652/article/details/82992555