资讯专栏INFORMATION COLUMN

synchronized锁了什么

fish / 2052人阅读

摘要:也有人称其为同步锁。既然是锁,其必然有锁的东西,下面先会简单介绍一下,再通过一个示例代码展示锁了什么。从而可以证明并不是锁定方法内访问的变量锁定的是同一个监视器对象监视的代码

前言

synchronized翻译为中文的意思是同步的,它是Java中处理线程安全问题常用的关键字。也有人称其为同步锁。既然是锁,其必然有锁的东西,下面先会简单介绍一下synchronized,再通过一个示例代码展示synchronized锁了什么。(这里先提前透露答案synchronized锁的是代码)

介绍 定义

synchronized提供的同步机制确保了同一个时刻,被修饰的代码块或方法只会有一个线程执行

用法

synchronized可以修饰方法和代码块:

修饰普通方法

修饰静态方法

修饰代码块

根据修饰情况,分为对象锁和类锁:

对象锁:

普通方法(等价于代码块修饰this

代码块修饰的是是类的一个对象

类锁

类方法(等价于代码块修饰当前类Class对象)

代码块修饰的是是类Class对象

原理

synchronized底层原理是使用了对象持有的监视器monitor)。但是同步代码块和同步方法的原理存在一点差异:

同步代码块是使用monitorentermonitorexit指令实现的

同步方法是由方法调用指令读取运行时常量池中方法的ACC_SYNCHRONIZED 标识隐式实现,实际上还是调用了monitorentermonitorexit指令

测试示例 计数器

一个特殊的计数器,自增方法increase()synchronized修饰,而获取当前值方法getCurrent()则没有被synchronized修饰。

/**
 * 计数器
 * @author RJH
 * create at 2019-03-13
 */
public class Counter {
    /**
     * 全局对象,总数
     */
    private static int i = 0;

    /**
     * 自增
     * @return
     */
    public synchronized int increase() {
        try {
            //使用休眠让结果更明显
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return ++i;
    }

    /**
     * 获取当前值
     * @return
     */
    public int getCurrent() {
        return i;
    }
}
测试代码

使用自增线程和获取当前值的线程来验证synchronized锁的是代码,而不是全局变量

/**
 * synchronized锁了什么
 * @author RJH
 * create at 2019-03-02
 */
public class LockWhatTest {

    public static void main(String[] args) {
        Counter counter =new Counter();
        IncreaseThread increaseThread1=new IncreaseThread(counter);
        IncreaseThread increaseThread2=new IncreaseThread(counter);
        GetThread getThread=new GetThread(counter);
        increaseThread1.start();
        increaseThread2.start();
        //直到increaseThread的线程启动才执行下一步
        while (increaseThread1.getState().compareTo(Thread.State.NEW)==0 && increaseThread1.getState().compareTo(Thread.State.NEW)==0){

        }
        getThread.start();
    }

    /**
     * 自增线程
     */
    static class IncreaseThread extends Thread{

        private Counter counter;

        public IncreaseThread(Counter counter) {
            this.counter = counter;
        }

        @Override
        public void run() {
            System.out.println("After increase:" + counter.increase()+",trigger time:"+System.currentTimeMillis());
        }
    }

    /**
     * 获取当前值的线程
     */
    static class GetThread extends Thread{

        private Counter counter;

        public GetThread(Counter counter) {
            this.counter = counter;
        }

        @Override
        public void run() {
            System.out.println("Current:"+ counter.getCurrent()+",trigger time:"+System.currentTimeMillis());
        }
    }

}
执行结果
Current:0,trigger time:1552487003845
After increase:1,trigger time:1552487008846
After increase:2,trigger time:1552487013848
结果分析

从测试结果可以得知

在两个自增线程启动后,获取当前值的线程才启动,但是获取当前值的线程是先被执行完成了。

根据自增线程执行完成的时间戳间隔可以得知,两个自增线程是依次执行的。

从而可以证明

synchronized并不是锁定方法内访问的变量

synchronized锁定的是同一个监视器对象监视的代码

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73688.html

相关文章

  • (十四)java多线程之死锁以及解决方案

    摘要:本人邮箱欢迎转载转载请注明网址代码已经全部托管有需要的同学自行下载引言多线程如果设计的不合理的话很可能就会出现死锁当两个或者多个线程同事想要去获取共享资源的锁时但每个线程都要等其他线程把他们各自的锁给释放才能继续运行这就是死锁出现死锁必须具 本人邮箱: 欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kcogithub: https://github...

    wendux 评论0 收藏0
  • Java中的读写锁

    摘要:如果这时其中一个等待读锁的线程被方法唤醒,但因为此时仍有请求写锁的线程存在,所以被唤醒的线程会再次进入阻塞状态。想要允许这样的操作,要求这个线程是唯一一个拥有读锁的线程。 假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁。在没有写操作的时候,两个线程同时读一个资源没有任何问题,所以应该允许多个线程能在同时读取共享资源。但是如果有一个线程想去写这些共享资源,就不...

    Alan 评论0 收藏0
  • 读写锁的java实现

    摘要:如何维护状态内部维护的读写状态是由位码表示,高位为读状态,表示持有读锁的线程数,低位为写状态,表示写锁的重入次数,状态的改变通过实现,保证同步。写锁降级到读锁有时拥有写锁的线程也希望得到读锁。 ReentrantReadWriteLock 如何保证同步 Java中的可重入读写锁ReentrantReadWriteLock是基于AQS(AbstractQueuedSynchronizer...

    233jl 评论0 收藏0
  • JAVA 7+ 实现自动锁(AutoLock)

    摘要:了解自动锁很早就受不了锁的机制了每次都需要在去解锁不仅代码不美观而且很麻烦我想能不能实现加锁之后自动解锁如果是可以利用析构函数实现但就想了想好像可以利用的特性对象只需要实现接口实现自动锁我了解如何利用特性写一个自动锁那么下面我们开始真正 了解自动锁 很早就受不了 java 锁的机制了,每次都需要在 finally 去解锁, 不仅代码不美观,而且很麻烦 我想能不能实现加锁之后自动解锁, ...

    Songlcy 评论0 收藏0
  • Java锁机制了解一下

    摘要:底层是是通过对象,对象有自己的对象头,存储了很多信息,其中一个信息标示是被哪个线程持有。当一个线程执行的代码出现异常时,其所持有的锁会自动释放。 前言 回顾前面: 多线程三分钟就可以入个门了! Thread源码剖析 多线程基础必要知识点!看了学习多线程事半功倍 只有光头才能变强! 本文章主要讲的是Java多线程加锁机制,有两种: Synchronized 显式Lock 不得不唠...

    hyuan 评论0 收藏0

发表评论

0条评论

fish

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<