答案:由于对象的内置锁(监视器锁)是唯一的,所以当线程一在访问对象的方法1时,持有了该对象的内置锁,那么再线程一释放该内置锁之前,其他线程是无法获取该对象内置锁,所以其他线程无法访问方法二。
/**
* 我们测试,如果统一个对象,有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
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时,该对象锁已经被线程一持有,则其他线程需等待该线程退出方法一,释放对象锁,才能进入被synchronized修饰的方法;
thread -- 0 执行方法1
thread -- 4 执行方法2
thread -- 3 执行方法2
thread -- 2 执行方法2
thread -- 1 执行方法2
/**
* 这是一个线程安全类
* @Author: dhcao
* @Version: 1.0
*/
public class SynchronizedInteger {
/** 定义属性 */
private int value;
public synchronized int getValue() {
return value;
}
public synchronized void setValue(int value) {
this.value = value;
}
}
若是没有前面的所说的synchronized的使用方法,那么有可能会认为这个类是线程不安全的。但是现在可知:当有线程在调用setValue方法时,由于它持有了对象的内置锁,那么其他线程是无法通过getValue方法访问到value值的。只有在set方法调用完成,value值更新,线程释放内置锁后,其他线程才能调用get方法,这时,value值已经更新了!
? 首先对内存的可见性要有一定的了解:
https://www.cnblogs.com/dhcao/p/10982278.html
工作线程和主内存的关系如上篇博客(虽然其他写得不太好,但是这个内存关系应该容易理解)。分别有x、y、z三条线程分别从主线程中读取数据a=1。那么对于线程x、y、z来说,a=1是独立的。即,当线程x执行a=2,那么线程y和线程z会知道a已经更新成为2了么。答案是不知道,因为在x执行a=2之前,线程y和z已经从主内存中加载了a=1这个信息。那么这是称为线程x和线程y、z的内存是不可见的!即:工作线程之间内存不可互相察觉!
? 但是通过上述分析我们可知,如果变量使用了synchronized来修饰。那么得到的内存结果是:当线程x在读取主内存中a=1信息时,由于对象锁被线程x持有,那么线程x、y只能等待,而不能从主内存中加载a=1这个信息。当x线程执行完set方法:a=2。然后将a=2这个值写到主内存中去,再释放对象的内置锁,此时线程x、y才能读取到主内存中的a的值,读取的结果是a=2。
? 这个现象我们可以理解为:线程x的工作内存将a=1修改为a=2。并且线程x、y知晓了这个修改。可以叫做线程x的内存对于线程y和z是可见的!
原文:https://www.cnblogs.com/dhcao/p/11567002.html