博客之星:我去,你竟然还不会用 synchronized(2)

简介: 博客之星:我去,你竟然还不会用 synchronized

02、synchronized 的用法


这么说吧,初学者在遇到多线程问题时,只要 synchronized 关键字使用得当,问题就能够迎刃而解。记得我刚回洛阳的时候,面试官问我,项目中是怎么解决并发问题的呢?我就说用 synchronized 关键字,至于其他的一些锁机制,我那时候还不知道。


嗯,面试官好像也不知道,因为小公司嘛,并发的量级有限,性能也不用考量得太过深入(大公司的读者可以呵呵了)。接下来,就随我来,一起看看 synchronized 最常见的三种用法吧。


1)直接用在方法上,就像下面这样:


public synchronized void synchronizedCalculate() {

   setSum(getSum() + 1);

}


修改一下测试用例:


@Test
void synchronizedCalculate() throws InterruptedException {
    ExecutorService service = Executors.newFixedThreadPool(3);
    SynchronizedMethod summation = new SynchronizedMethod();
    IntStream.range(0, 1000)
            .forEach(count -> service.submit(summation::synchronizedCalculate));
    service.awaitTermination(1000, TimeUnit.MILLISECONDS);
    assertEquals(1000, summation.getSum());
}



这时候,再运行测试用例就通过了。因为 synchronized 关键字会对 SynchronizedMethod 对象进行加锁,同一时间内只允许一个线程对 sum 进行修改。这就好像有一间屋子,线程进入屋子里面才可以对 sum 加 1,而 synchronized 就相当于在门上加了一个锁,一个线程进去后就锁上门,修改完 sum 后,下一个线程再进去,其他线程就在门外候着。


2)用在 static 方法上,就像下面这样:


public class SynchronizedStaticMethod {
    public static int sum;
    public synchronized static void synchronizedCalculate() {
        sum = sum + 1;
    }
}



sum 是一个静态变量,要修改静态变量的时候,就需要把方法也变成 static 的。


来新建一个测试用例:


class SynchronizedStaticMethodTest {
    @Test
    void synchronizedCalculate() throws InterruptedException {
        ExecutorService service = Executors.newFixedThreadPool(3);
        IntStream.range(0, 1000)
                .forEach(count -> service.submit(SynchronizedStaticMethod::synchronizedCalculate));
        service.awaitTermination(1000, TimeUnit.MILLISECONDS);
        assertEquals(1000, SynchronizedStaticMethod.sum);
    }
}



静态方法上添加 synchronized 的时候就不需要实例化对象了,直接使用类名就可以引用方法和使用变量了。测试用例也是可以通过的。


synchronized static 和 synchronized 不同的是,前者锁的是类,同一时间只能有一个线程访问这个类;后者锁的是对象,同一时间只能有一个线程访问方法。


3)用在方法块上,就像下面这样:


public void synchronisedThis() {
    synchronized (this) {
        setSum(getSum() + 1);
    }
}


这时候,将 this 传递给了 synchronized 代码块,当在某个线程中执行这段代码块,该线程会获取 this 对象的锁,从而使得其他线程无法同时访问该代码块。如果方法是静态的,我们将传递类名代替对象引用,示例如下所示:


public static void synchronisedThis() {
    synchronized (SynchronizedStaticMethod.class) {
        sum = sum + 1;
    }
}


新建一个测试用例:


@Test
void synchronisedThis() throws InterruptedException {
    ExecutorService service = Executors.newFixedThreadPool(3);
    SynchronizedMethod summation = new SynchronizedMethod();
    IntStream.range(0, 1000)
            .forEach(count -> service.submit(summation::synchronisedThis));
    service.awaitTermination(1000, TimeUnit.MILLISECONDS);
    assertEquals(1000, summation.getSum());
}



测试用例和 synchronized 方法的大差不差,运行后也是可以通过的。两者之间有所不同,synchronized 代码块的锁粒度要比 synchronized 方法小一些,因为 synchronized 代码块所在的方法里还可以有其他代码。


image.png


好了,我亲爱的读者朋友,以上就是本文的全部内容了,synchronized 的三种用法你一定掌握了吧?觉得文章有点用的话,请微信搜索「沉默王二」第一时间阅读。


本文 GitHub 已经收录,有大厂面试完整考点,欢迎 Star。

我是沉默王二,一枚有趣的程序员,关注即可提高学习效率。最后,请无情地点赞、收藏、留言吧,谢谢。

相关文章
|
程序员
博文创作者都有一个拥有自己专属博客梦
经常写作的作者想必都知道,个人博客是一种历史悠久的网站形态,它能够让我们更好地表达自己的想法和思考,与读者进行互动和交流。在互联网发展的今天,个人博客仍然是一种流行的媒介,而且许多人都拥有自己的个人博客。作为程序员更是如此,要有属于自己的技术博客。
174 2
博文创作者都有一个拥有自己专属博客梦
|
Java 测试技术
博客之星:我去,你竟然还不会用 synchronized(1)
博客之星:我去,你竟然还不会用 synchronized
108 0
博客之星:我去,你竟然还不会用 synchronized(1)
|
资源调度 Java 调度
|
安全 JavaScript 测试技术
|
iOS开发 开发者 Swift
我的2016 “CSDN博客之星” 韩俊强的博客
2016年12月31日         时间如白驹过隙,转眼间2016年的尾巴快要抓不住了。总结一下这一年的自我价值和工作业绩,不知该如何下笔,因为不知道自己奋斗的是否还是年初的目标。大家都知道2016雾霾一直驱之不散,作为开发人员,这一年也是在紧迫的情景下进行的,时而被各种裁员新闻所忧虑,时而被“996”所困扰,但是我们在成长,不能被外界所困。
1126 0
每天必须膜拜的博客
网易云风(现已和朋友同事创业,目前已渡过初创期) http://blog.codingnow.com/   日本工作猫 https://onevcat.com/2013/07/shader-tutorial-1/