曾经有一个比较有趣的面试问题,那就是,关于使用synchronized关键字,是用在方法上面尾号,还是用在一个代码块上面为好?

答案就是使用锁定代码块为更好。因为这样不会锁定对象。当synchronized关键字在实例方法的上面时,线程对于该方法的访问会直接锁定整个对象,参考如下代码:

class Sync {
public synchronized void syncMethod() {
System.out.println("Sync Method Executed");
} public void syncThis() {
synchronized (this) {
System.out.println("Sync This Executed");
}
}
}

上面的类中,syncMethod()syncThis()方法,是没有区别的。为了验证这个说法,参考如下代码:

package net.ethanpark.common.task;

/**
* Author: EthanPark <br/>
* Date: 2016/11/27<br/>
*/
public class SyncTest {
public static void main(String[] args) {
Sync sync = new Sync(); Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
sync.syncMethod();
}
}); Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
sync.syncThis();
}
}); t1.start();
t2.start();
}
} class Sync {
public synchronized void syncMethod() {
System.out.println("Sync Method Start To Executed");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Sync Method Executed");
} public void syncThis() {
synchronized (this) {
System.out.println("Sync This Executed");
}
}
}

再说上面的代码中,我启动了两个线程,分别执行syncMethod()syncThis()方法,其中syncMethod()方法会等待5秒,然后才执行结束。以下是输出的结果:

Sync Method Start To Executed
Sync Method Executed
Sync This Executed

t1和t2是先后启动的,如果syncMethod()方法没有锁定Sync对象的话,syncThis()方法肯定会更优先的执行,但是syncThis()方法从输出来看,在获取this对象的锁的时候,阻塞了,直到syncMethod()全部执行完毕才开始执行,所以才有如上的输出。

在考虑前面那个问题就清晰了,synchronized直接加在方法上面,会锁定整个对象,也就是说,如果对象中有一些字段是不需要同时来同步的,synchronized关键字也会阻止其他线程来获取该对象的锁,从而令其他线程阻塞而无法达到高吞吐量。

当然,synchronized关键字对对象加锁,也只有其他对象也在请求对象锁的时候才会阻塞的,如果其他对象不需要请求对象锁,而是直接访问非同步变量,还是允许的。针对之前的代码我增加了一个新的线程和一个新的方法notSyncMethod():

package net.ethanpark.common.task;

/**
* Author: EthanPark <br/>
* Date: 2016/11/27<br/>
*/
public class SyncTest {
public static void main(String[] args) {
Sync sync = new Sync(); Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
sync.syncMethod();
}
}); Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
sync.syncThis();
}
}); Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
sync.notSyncMethod();
}
}); t1.start();
t2.start();
t3.start();
}
} class Sync {
public synchronized void syncMethod() {
System.out.println("Sync Method Start To Executed");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Sync Method Executed");
} public void syncThis() {
synchronized (this) {
System.out.println("Sync This Executed");
}
} public void notSyncMethod(){
System.out.println("Not Sync Method Executed");
}
}

程序的输出如下:

Sync Method Start To Executed
Not Sync Method Executed
Sync Method Executed
Sync This Executed

从第一行输出来看,t1其实已经获得了sync对象的对象锁,但是notSyncMethod()方法仍然是可以执行的。

需要注意的是,synchronized方法也是可以加在静态方法上面的。然而加在静态方法上面和加在实例方法上面,两者是不会使得线程互斥的。原因很简单,针对实例方法同步,我们请求的是对象锁,而静态方法的访问,是不针对对象的,所以两者是不会冲突的。针对静态方法的同步,实际上跟针对类型的同步是一致的。参考如下代码:

package net.ethanpark.common.task;

/**
* Author: EthanPark <br/>
* Date: 2016/11/27<br/>
*/
public class SyncTest {
public static void main(String[] args) {
Sync sync = new Sync(); Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
sync.syncMethod();
}
}); Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
Sync.staticSyncMethod();
}
}); Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
Sync.staticTypeMethod();
}
}); t1.start();
t2.start();
t3.start();
}
} class Sync {
public synchronized void syncMethod() {
System.out.println("Sync Method Start To Executed");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Sync Method Executed");
} public synchronized static void staticSyncMethod(){
System.out.println("Static Sync Method Start To Executed");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Static Sync Method Executed");
} public static void staticTypeMethod(){
synchronized (Sync.class){
System.out.println("Static Sync Type Executed");
}
}
}

上面代码的输出如下:

Sync Method Start To Executed
Static Sync Method Start To Executed
Static Sync Method Executed
Static Sync Type Executed
Sync Method Executed

可以看出,在staticSyncMethod()staticTypeMethod()两者是等同的,当staticSyncMethod()执行的时候,staticTypeMethod()是阻塞的。而两个静态的方法,跟实例的方法是完全互不影响的。

Java线程和多线程(十四)——Synchronized关键字解析的更多相关文章

  1. java提高篇(十四)-----关键字final

    在程序设计中,我们有时可能希望某些数据是不能够改变的,这个时候final就有用武之地了.final是java的关键字,它所表示的是"这部分是无法修改的".不想被改变的原因有两个:效 ...

  2. java线程池 多线程搜索文件包含关键字所在的文件路径

    文件读取和操作类 import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; publi ...

  3. Java线程和多线程(四)——主线程中的异常

    作为Java的开发者,在运行程序的时候会碰到主线程抛异常的情况.如果开发者使用Java的IDE比如Eclipse或者Intellij IDEA的话,可能是不需要直接面对这个问提的,因为IDE会处理运行 ...

  4. JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制

    JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是clas ...

  5. Java中的集合(十四) Map的实现类LinkedHashMap

    Java中的集合(十四) Map的实现类LinkedHashMap 一.LinkedHashMap的简介 LinkedHashMap是Map接口的实现类,继承了HashMap,它通过重写父类相关的方法 ...

  6. Java 设计模式系列(十四)命令模式(Command)

    Java 设计模式系列(十四)命令模式(Command) 命令模式把一个请求或者操作封装到一个对象中.命令模式允许系统使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复 ...

  7. 程序员Java架构师多线程面试题和回答解析

    当我们在Java架构师面试的过程中常见的多线程和并发方面的问题肯定是必不可少的一部分.那么在面试之前我们更应该多准备一些关于多线程方面的问题. 面试官只是想确信面试者有足够的Java线程与并发方面的知 ...

  8. synchronized 关键字解析

    synchronized 关键字解析 同步锁依赖于对象,每个对象都有一个同步锁. 现有一成员变量 Test,当线程 A 调用 Test 的 synchronized 方法,线程 A 获得 Test 的 ...

  9. Java多线程4:synchronized关键字

    原文:http://www.cnblogs.com/skywang12345/p/3479202.html 1. synchronized原理在java中,每一个对象有且仅有一个同步锁.这也意味着,同 ...

随机推荐

  1. ORACLE数据库AWR工具学习

    AWR(Automatic Workload Repository)即工作负载信息库,主要用于收集数据库运行状态的资料库,通过AWR报告可以分析ORACLE数据库的性能,从而给出优化策略. 图一:此图 ...

  2. C++易混淆概念

    1. 引用和指针有什么区别? 本质:一个是别名,一个是地址1. 指针可以在运行时改变其所指向的值,引用一旦和某个对象绑定就不再改变2. 引用没有const, 指针有const 3. 从内存上看,指针会 ...

  3. [CENTOS7] 加入Windows域

    This following article is a snapshot from: https://www.rootusers.com/how-to-join-centos-linux-to-an- ...

  4. LocationCoder 地图经纬度解析

    LocationCoder 地图经纬度解析 其实,在地图里面将地图解析成有意义的地址,或者把地址转换成有意义的经纬度都是很容易的事情,只是我将其封装了支持KVO,通知中心,block取结果,代理取结果 ...

  5. oracle 复制表结构 复制表数据 sql 语句

    1. 复制表结构及其数据: create table table_name_new as select * from table_name_old 2. 只复制表结构: create table ta ...

  6. SQL Server中搜索特定的对象

    一.注释中带某关键字的对象 主要用到 sys.tables .sys.columns .sys.procedures  系统对象表以及sys.extended_properties 扩展属性表 --查 ...

  7. 你的ABAP程序给佛祖开过光么?来试试Jerry这个小技巧

    最近Jerry在忙一个项目,技术栈换成了nodejs平台,语言换成了JavaScript,因为赶项目进度,一直没时间更新公众号.感谢大家的支持,关注人数还是慢慢地增长到了3000. 今天我们来聊聊一个 ...

  8. mysql workbench的PK,NN,UQ,BIN,UN,ZF,AI

    mysql workbench建表时PK.NN.UQ.BIN.UN.ZF.AI的意思,后面几个老搞不清,随记在这便于以后方便查. [intrinsic column flags] (基本字段类型标识) ...

  9. 【问题定位】tcpdump 抓包简易命令

    tcpdump -A -i lo port 2003 or port 2103 or port 2203 | grep '.*system.*'

  10. 【原创】python requests 库底层Sockets处于close_wait状态

    以前对于Requests库只是简单是使用,在现在公司的后台中,有多个接口是直接使用requests.get .post之类的方法来做的,进行过一段时间的压力测试,发现性能低的可怜,且linux服务器有 ...