Java并发编程(二)synchronized关键字

注意

以下内容源自互联网相关资料及本人学习与工作经验,仅为学习及技术分享所用,切勿用于商业用途,转载请注明出处。

1. 线程同步

多个线程之间可能会竞争相同的资源,比如两个读取数据库操作的线程就会竞争数据库连接这个资源,这个被竞争的资源叫作共享资源或者临界资源。如何协调各个线程对共享资源的使用,称为线程同步。线程同步需要考虑以下几点:

  • 存在竞争就需要同步,同步的概念指的不是同时执行,而是协同步调,按一定的规矩将线程“排队”,确定好“谁先消费共享资源”,而这个规矩必须满足于业务的要求。
  • 共享资源才需同步,只有共享资源的读写访问才需要同步。如果不是共享资源,那么就根本没有同步的必要。
  • 只对“变量”进行同步,只有“变量”(这里的变量指的是资源存在可变性)才需要同步访问。如果共享的资源是固定不变的,那么就相当于“常量”,线程同时读取常量也不需要同步。至少一个线程修改共享资源,这样的情况下,线程之间就需要同步。
  • 共享资源并非同份代码,多个线程访问共享资源的代码有可能是同一份代码,也有可能是不同的代码;无论是否执行同一份代码,只要这些线程的代码访问同一份可变的共享资源,这些线程之间就需要同步。

2. synchronized关键字

Java提供了原生的synchronized关键字来修饰临界资源,对共享资源加锁,使同一时间只能有一个线程得到共享资源,其它线程只能阻塞等待该线程释放共享资源后,才可以重新竞争获得共享资源的机会。
有一个线典的例子:多个人上公厕,假设只有一个坑位,这里的坑位就是共享资源,多个人就是多个线程,同时只能有一个人竞争得到上坑的机会,上坑后,这个人会把厕所门锁上,其他人只能在外等这个人上完厕所后,打开厕所后,才能“蜂拥而上”竞争下一次上坑的机会。在这个例子里,厕所门锁就相当于synchronized关键字,它将厕所这个共享资源加上了锁,同时能允许一个线程进入。

2.1 用法1 synchronized修饰实例方法

synchronized修饰实例方法,锁是加在这个方法的实例对象上的,当多个线程访问同一个实例对象的这个方法时,只能有一个线程进入该方法。注意:这种场景下,一个实例对象对应一把锁,多个线程只有调用同一个实例对象时才有意义。
下面的代码是synchroinzed修饰实例方法的例子:

public synchronized void addCount(){
        for(int i = 0;i<50;i++){
            count +=1;
        }
    }

2.2 用法2 synchronized修饰静态方法

synchronized修饰静态方法与修饰实例方法在语法上是相同的,参见下例:

public synchronized static void addCount(){
        for(int i = 0;i<50;i++){
            count +=1; //count必须为静态变量
        
        }
    }

我们知道,在JVM中每一个类只存在一个类对象(class object),在这种场景下,synchronized所加的锁就在修饰的静态方法所属的类对象上,所有线程调用此静态方法时,同一时间只有一个线程能获得这把锁,进行这个静态方法。

2.3 用法3 synchronized修饰实例方法内代码块

上面示例代码中,共享资源其实只是count这个变量,我们没有必要对整个方法加锁,这样反而会影响整个程序的执行效率,这时候,我们可以将synchronized关键字加在操作count变量的代码块上,实现更细粒度的控制。如下:

public void addCount(){
        for(int i = 0;i<50;i++){
            synchronized(this){
                          count +=1;
                        }
        }
    }

synchronized修饰代码块时,需要指定一个“监视对象”(monitor object),也就是要对哪个对象加锁。上面示例代码中使用this指向本实例对象,表示对实例对象加锁,多个线程访问此实例对象时,只能有一个线程进行synchronized修饰的代码块。
监视对象不一定要是this,也可以是任何对象,如下例所示:

public final Object monitor = new Object();//final修饰,表示监视对象不可变
public void addCount(){
        for(int i = 0;i<50;i++){
            synchronized(monitor){
                          count +=1;
                        }
            
        }
    }

上例中,我们用final修饰了监视对象,为什么呢?因为monitor这个变量实际是只是指向监视对象所在内存中的地址,如果不修饰成final的话,当我们修改这个monitor变量,让它指向其他对象,比如 在synchronized代码块中,我们让monitor指向其他对象(monitor = new OtherObject();) 那么monitor就不是原本我们指定的监视对象了,锁也就失去了意义。
如果监视对象不是同一个实例对象的话,则表示有多个不同的锁,不同的线程可以进入不同的锁限制的代码块。

2.4 用法4 synchronized修饰静态方法内代码块

同样也可以使用synchronized来修饰静态方法内的代码块,此时监视对象必须是类对象(class object)。
注意,如果监视的类对象不同,则表示有多个不同的锁,不同的线程可以进入不同的锁限制的代码块。

public synchronized static void addCount(){
        for(int i = 0;i<50;i++){
                synchronized(SynchronizedUsage.class){//SynchronizedUsage.class是类对象
            count +=1; //count必须为静态变量
                 }
        }
    }

2.5 释放锁的两种情况

如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:

  • 获取锁的线程执行完了该代码块,然后线程释放对锁的占有。
  • 线程执行发生异常,此时JVM会让线程自动释放锁。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容