曾经有一个比较有趣的面试问题,那就是,关于使用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()是阻塞的。而两个静态的方法,跟实例的方法是完全互不影响的。

最新文章

  1. 静态属性,直接把iis搞垮掉 Http error 503 Service Unavailable
  2. [skill][gdb] gdb 多线程调试
  3. 常用SVN命令
  4. SQL排序
  5. PHP链式操作输出excel(csv)
  6. Trying to hack Redis via HTTP requests
  7. Java学习----有风险的代码(异常)
  8. 2015第10周三jquery ui position
  9. Sqlserver 2008安装
  10. 【转】shell中如何判断一个变量是否为空
  11. 了解Scala 宏
  12. vue + element 动态渲染、移除表单并添加验证
  13. Elasticsearch.Net、Nest批量插入BulkAll
  14. 关于activity的一点总结(一)
  15. 剪格子---(dfs回溯)
  16. svn st 状态详解
  17. 如何使用swfobject(中文版)
  18. [LeetCode&amp;Python] Problem 598. Range Addition II
  19. linux 常用命令(个人记录)
  20. go学习笔记-环境安装

热门文章

  1. python函数修饰器(decorator)
  2. 在asp.net一般应用程序中使用session
  3. 【MySQL】sysbench压测服务器及结果解读
  4. [翻译] PPiAwesomeButton
  5. Apache下开启SSI配置,使html支持include包含
  6. eclipse中 项目--&gt;属性--&gt;为什么没有deployment assembly 选项
  7. php请求页面将返回的页面发送email
  8. Anaconda 安装和使用
  9. PHP eval() 函数
  10. BZOJ2694:Lcm——包看得懂/看不懂题解