问:当一个对象中有2个方法同时用synchronized修饰,那么当线程一在访问方法1时,其他线程是否可以访问方法二?
答案:由于对象的内置锁(监视器锁)是唯一的,所以当线程一在访问对象的方法1时,持有了该对象的内置锁,那么再线程一释放该内置锁之前,其他线程是无法获取该对象内置锁,所以其他线程无法访问方法二。
验证一:只有方法一使用synchroized修饰时,其他线程可以随意访问方法二。
/**
* 我们测试,如果统一个对象,有2个方法都使用synchronized。
* 验证:每个对象有唯一的对象锁;(称为:内置锁或监视器锁)
* 那么当线程一在访问方法一时,已经持有方法该对象锁。
* 其他线程若想执行方法二,必须等待线程一释放该对象锁。
* @Author: dhcao
* @Version: 1.0
*/
public class SynchronizedFac {
public synchronized void methodOne() throws Exception {
String threadName = Thread.currentThread().getName();
Thread.sleep(3000);
System.out.println(threadName + " 执行方法1");
}
/**
* 第一次测试,方法二不加锁,我们预期:
* 当线程一执行方法1时,其他线程是可以访问方法二的。
*/
public void methodTwo() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 执行方法2");
}
public static void main(String[] args) throws Exception{
// 保证对象相同
final SynchronizedFac fac = new SynchronizedFac();
for (int i = 0; i < 5; i++) {
// 我们让线程一来访问方法一
if (i == 0) {
new Thread(new Runnable() {
public void run() {
try {
fac.methodOne();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "thread -- " + i).start();
}else{
// 其他线程则访问方法二
new Thread(new Runnable() {
public void run() {
try {
fac.methodTwo();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "thread -- " + i).start();
}
}
}
}
运行结果:由于方法1中有线程等待,所以其他线程率先执行完了方法二
thread -- 1 执行方法2
thread -- 2 执行方法2
thread -- 3 执行方法2
thread -- 4 执行方法2
thread -- 0 执行方法1
验证二:方法一和方法二同时使用synchroized修饰时,必须等线程一释放对象锁之后其他线程才能获取锁访问方法二。
package org.dhcao.relax.synchronizedOneInstance;
/**
* 我们测试,如果统一个对象,有2个方法都使用synchronized。
* 验证:每个对象有唯一的对象锁;(称为:内置锁或监视器锁)
* 那么当线程一在访问方法一时,已经持有方法该对象锁。
* 其他线程若想执行方法二,必须等待线程一释放该对象锁。
* @Author: dhcao
* @Version: 1.0
*/
public class SynchronizedFac {
public synchronized void methodOne() throws Exception {
String threadName = Thread.currentThread().getName();
Thread.sleep(3000);
System.out.println(threadName + " 执行方法1");
}
/**
* 第二次测试,方法二加锁,我们预期:
* 当线程一执行方法1时,其他线程是不可以访问方法二的;
* 必须等待线程一释放锁
*/
public synchronized void methodTwo() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " 执行方法2");
}
public static void main(String[] args) throws Exception{
final SynchronizedFac fac = new SynchronizedFac();
for (int i = 0; i < 5; i++) {
// 我们让线程一来访问方法一
if (i == 0) {
new Thread(new Runnable() {
public void run() {
try {
fac.methodOne();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "thread -- " + i).start();
}else{
// 其他线程则访问方法二
new Thread(new Runnable() {
public void run() {
try {
fac.methodTwo();
} catch (Exception e) {
e.printStackTrace();
}
}
}, "thread -- " + i).start();
}
}
}
}
执行结果:在线程1(thread — 0)访问方法1时,该对象锁已经被线程一持有,则其他线程需等待该线程退出方法一,释放对象锁,才能进入被synchorized修饰的方法;
thread -- 0 执行方法1
thread -- 4 执行方法2
thread -- 3 执行方法2
thread -- 2 执行方法2
thread -- 1 执行方法2