博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java中两个线程是否可以同时访问同一个对象的两个不同的synchronized方法?
阅读量:6293 次
发布时间:2019-06-22

本文共 4463 字,大约阅读时间需要 14 分钟。

不可以!!!

多个线程访问同一个类的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();    }}

 

转载于:https://www.cnblogs.com/Jackie-zhang/p/10384136.html

你可能感兴趣的文章
《MongoDB管理与开发精要》——1.4节本章小结
查看>>
美国防部报告传指联想产品带来网络威胁
查看>>
php实现查询功能
查看>>
IBM拓展云数据分析服务 用户来“做主”
查看>>
迁移到云端的企业数据需注意安全
查看>>
不仅要“打假”,Facebook 还要治理视频直播中的裸露、暴力内容
查看>>
非授权频谱NB-IoT将引发市场格局突变
查看>>
2017全球中国锂电池市场趋势概述
查看>>
雅虎成立特别委员会评估新战略选项
查看>>
从IBM SVF看传统存储改造的三大要点:软件定义、容量与速度
查看>>
监控摄像头使用率不足六成 还需提高维护力
查看>>
《C语言程序设计:问题与求解方法》——1.4节本章习题
查看>>
交互式线上科学期刊Distill上线,Ian Goodfellow表示“学ML就找它”
查看>>
区块链:这项颠覆性技术将如何改变未来
查看>>
新致云产品运营的那些小事
查看>>
分析师洞察:边缘数据中心的UPS系统
查看>>
微软修复20多年的老漏洞:Win95时就存在了
查看>>
58回应“简历数据泄露”:将展开追查并加固安全系统
查看>>
大数据如何重构影视行业产业链
查看>>
MaxCompute(原ODPS) Studio 2.7.0 版本发布,让代码效率更高
查看>>