Java中同一个类中不同的synchronized方法是否可以并发执行 ??


更通俗简单的问法: "Java中两个线程是否可以同是否问一个对象的两个不同的synchronized方法????"

答案是: 不可以!!!

也许这个问题在你看来显而易见, 但是我却一直以为:

~~几个不同线程同时访问某个类的同一个synchronized方法时, 一个线程执行时, 其他线程都等待; 若是几个不同线程访问的是一个类不同的synchronized, 则可以同时执行. ~~

让大神们见笑了~~

======
但是如果你也有和我一样的观念, 那么就请仔细阅读下面的文字!!

多个线程访问同一个类的synchronized方法时, 都是串行执行的 ! 就算有多个cpu也不例外 ! synchronized方法使用了类java的内置锁, 即锁住的是方法所属对象本身. 同一个锁某个时刻只能被一个执行线程所获取, 因此其他线程都得等待锁的释放. 因此就算你有多余的cpu可以执行, 但是你没有锁, 所以你还是不能进入synchronized方法执行, CPU因此而空闲. 如果某个线程长期持有一个竞争激烈的锁, 那么将导致其他线程都因等待所的释放而被挂起, 从而导致CPU无法得到利用, 系统吞吐量低下. 因此要尽量避免某个线程对锁的长期占有 !

下面给出验证代码, 君自斟酌:

public class SyncMethod {

    public synchronized void syncMethod2() {
        try {
            System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 已经获取内置锁`SyncMethod.this`)");
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 即将释放内置锁`SyncMethod.this`)");
    }

    public synchronized void syncMethod1() {
        System.out.println("######################## (syncMethod1, 已经获取内置锁`SyncMethod.this`, 并即将退出)");
    }


    static class Thread1 extends Thread {
        SyncMethod syncMethod;

        public Thread1(SyncMethod syncMethod) {
            this.syncMethod = syncMethod;
        }

        @Override
        public void run() {
            syncMethod.syncMethod2();
        }
    }

    static class Thread2 extends Thread {
        SyncMethod syncMethod;

        public Thread2(SyncMethod syncMethod) {
            this.syncMethod = syncMethod;
        }

        @Override
        public void run() {
            System.out.println("Thread2 running ...");
            syncMethod.syncMethod1();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SyncMethod syncMethod = new SyncMethod();
        Thread1 thread1 = new Thread1(syncMethod);
        Thread2 thread2 = new Thread2(syncMethod);

        thread1.start();    //先执行, 以便抢占锁
        Thread.sleep(500); //放弃cpu, 让thread1执行, 以便获的锁

        thread2.start(); //在syncMethod1()方法获得锁时, 看看syncMethod2()方法能否执行

        /*
        能否并发执行同一个对象不同的synchronized方法, 即看看能否同时进入一个对象synchronized方法块

        1. 创建一个有两个synchronized方法的对象`syncMethod`
        2. 先启动一个线程(Thread1), 并让其进入syncMethod对象的sychronized方法(syncMethod1)内, 并使其停在synchronized方法内
        3. 再启动一个线程(Thread2), 并执行syncMethod对象的一个synchronized方法(syncMethod2), 看看能否进入此方法内

        输出如下: 
        @@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 已经获取内置锁`SyncMethod.this`)
        Thread2 running ...
        @@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 即将释放内置锁`SyncMethod.this`)
        ######################## (syncMethod1, 已经获取内置锁`SyncMethod.this`, 并即将退出)

        结果分析: 
            观察显示, 在输出`Thread2 running ...`后会暂停数秒(Thread2无法获得所而被挂起, 因为锁已经被Thread1持有).
            
            如果不同线程可以同时访问同一个对象不同synchronized方法的话, 
            在有足够cpu时间片时(Thread1在调用syncMethod1时使用Thread.sleep放弃了cpu), 
            Thread2调用的syncMethod2方法应该马上执行, 也就是syncMethod2方法中的语句在`Thread2 running ...`语句输出后马上输出, 
            而不是等待数秒才输出 (应为此时没有其他线程跟Thread2竞争cpu, 况且现在的电脑都不只一个cpu), 
            因此得出结论: "不同线程不能同时执行一个对象的不同synchronized方法"
        
            其实此结论是显而易见的, 原理前面已经阐明, 此处不再赘述.
        */

    }
}

下面是一些关于使用锁的一些建议:
为了避免对锁的竞争, 你可以使用锁分解,锁分段以及减少线程持有锁的时间, 如果上诉程序中的syncMethod1和syncMethod2方法是两个不相干的方法(请求的资源不存在关系), 那么这两个方法可以分别使用两个不同的锁, 改造后的SyncMethod类如下:

public class SyncMethod {
    private Object lock1 = new Object();
    private Object lock2 = new Object();
    
    public void syncMethod2() {
        synchronized (lock1) {
            try {
                System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 已经获取内置锁`SyncMethod.this`)");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 即将释放内置锁`SyncMethod.this`)");
        }
    }

    public void syncMethod1() {
        synchronized (lock2) {
            System.out.println("######################## (syncMethod1, 已经获取内置锁`SyncMethod.this`, 并即将退出)");
        }
    }
}

改造之后Thread1和Thread2就不会发生, 由于锁竞争而挂起的情况了.

当然, 如果syncMethod1中耗时操作与锁定的资源无关, 那么也可以将耗时操作移出同步块. 在上述改造的基础上对syncMethod1的进一步改造如下:

public void syncMethod2() {
    synchronized (lock1) {
        System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 已经获取内置锁`SyncMethod.this`)");
        System.out.println("@@@@@@@@@@@@@@@@@@@@@@@@ (syncMethod2, 即将释放内置锁`SyncMethod.this`)");
    }


    //将耗时操作移出同步块
    try {
        Thread.sleep(5000);//与同步使用的资源无关的耗时操作
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

.
关于并发编程, 圣经在此 => 《Java并发编程实战》
有些观念生而有之, 久而久之,我们就认为它们是对的合理的,然而并非如此。如果某一天你对某个曾经深信不疑的观念有了疑问, 那么赶紧行动起来,请用你的理性思考它,验证它。

共勉!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容