Java中两个线程是否可以同时访问同一个对象的两个不同的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中两个线程是否可以同时访问同一个对象的两个不同的synchronized方法?的更多相关文章
- Java中如何创建线程
Java中如何创建线程 两种方式:1)继承Thread类:2)实现Runnable接口. 1.继承Thread类 继承Thread类,重写run方法,在run方法中定义需要执行的任务. class M ...
- Java中的守护线程 & 非守护线程(简介)
Java中的守护线程 & 非守护线程 守护线程 (Daemon Thread) 非守护线程,又称用户线程(User Thread) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守 ...
- Java中正确终止线程的方法
Thread类中有一个已经废弃的 stop() 方法,它可以终止线程,但由于它不管三七二十一,直接终止线程,所以被废弃了.比如,当线程被停止后还需要进行一些善后操作(如,关闭外部资源),使用这个方法就 ...
- 设计四个线程,当中共两个线程每次对j添加1,另外两个线程每次对j降低1。循环100次,写出程序。
package cn.usst.DataTest6; /** * 设计四个线程,当中共两个线程每次对j添加1,另外两个线程每次对j降低1.循环100次,写出程序. * @ * */ public cl ...
- 设计 4 个线程,其中两个线程每次对 j 增加 1 ,另外两个线程对 j 每次减少 1 。写出程序。
题目:设计 4 个线程,其中两个线程每次对 j 增加 1 ,另外两个线程对 j 每次减少 1 .写出程序. 代码实现 public class ThreadTest{ private int j; c ...
- java 多线程访问同一个对象数据保护的问题
java 多线程同时访问统一个数据的时候,会引起一些错误,后面的线程会修改数据,而前面的线程还在使用修改前的内容, 使用 synchronized 关键字,保证代码块只能有一个线程来访问 public ...
- 关于Java中进程和线程的详解
一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而 ...
- Java中怎样创建线程安全的方法
面试问题: 下面的方法是否线程安全?怎样让它成为线程安全的方法? class MyCounter { private static int counter = 0; public static int ...
- Java中的守护线程和非守护线程(转载)
<什么是守护线程,什么是非守护线程> Java有两种Thread:"守护线程Daemon"(守护线程)与"用户线程User"(非守护线程). 用户线 ...
随机推荐
- jar包不能乱放【浪费了下午很多时间】
不能放在类路径下(也即是src文件夹下),然后再buildpath 必须放在web-inf文件夹下 这样才能tomcat找打jar文件
- oracle-pl/sql之三
集合与记录 set serveroutput on create or replace package my_types authid definer is type my_rec is record ...
- Docker Images for MySQL Group Replication 5.7.14
In this post, I will point you to Docker images for MySQL Group Replication testing. There is a new ...
- c++11 function_typetraits备忘
function traits. 获取函数或成员函数的返回类型,参数类型,参数长度,类类型. 函数参数列表推断基于typelist:http://www.cnblogs.com/flytrace/p/ ...
- 【python】变量的赋值、深浅拷贝
python——赋值与深浅拷贝 https://www.cnblogs.com/Eva-J/p/5534037.html 啥都不说,看这个博主的文章!
- centos7-软件安装-mysql5.7
mysql5.7新增特点: 最新版本的mysql5.7相比较于mysql5.6,新添加了一个特点:允许日期类型字段添加数值精确到毫秒位数,比如`create_date` datetime(3) DEF ...
- 在Docker中监控Java应用程序的5个方法
译者注:Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化.通常情况下,监控的主要目的在于:减少宕机 ...
- python开发购物车
1 业务需求 商品中心 显示库存的商品 商品能够加入到购物车 个人中心 购物车 修改购物车的商品 下单 完成的订单 订单详情 账户余额 2 代码实现 # 定义全局变量信息 # 商品编号信息 goods ...
- Scrapy学习篇(十)之下载器中间件(Downloader Middleware)
下载器中间件是介于Scrapy的request/response处理的钩子框架,是用于全局修改Scrapy request和response的一个轻量.底层的系统. 激活Downloader Midd ...
- Django Forms 表单
环境 python 3.7 服务端 views.py from django import forms # 引入 froms 模块 from django.forms import widgets ...