原文链接:
https://blog.csdn.net/u011676300/article/details/79076990
当一个线程调用一个对象的同步方法(synchronized修饰)时,其获得的是对象锁(其他线程无法访问该对象的所有方法),还是获得的是对象方法的锁(其他线程只是无法访问该方法而已)。
也就是说,有一个类有三个方法,其中两个为同步方法.另一个为非同步方法.
当有两个线程Thread0和Thread1,Thread0在调用fun1()时,可以确定的是Thread1也是无法调用fun1()的.
但是Thread1能不能够调用fun2和fun3呢?
class test{
public synchronized void fun1()
{}
public void fun2()
{}
public synchronized void fun3()
{}
}
验证代码1:
public class VerifyThread {
public static void main(String[] args) {
ValueTest ValueC = new ValueTest();
MyThread thread0 = new MyThread(ValueC);
MyThread thread1 = new MyThread(ValueC);
thread0.start();
thread0.valclass.setValue(100);
thread1.start();
}
}
class MyThread extends Thread{
ValueTest valclass;
public MyThread(ValueTest valclass) {
this.valclass = valclass;
}
@Override
public void run() {
System.out.println("线程名称:" + Thread.currentThread().getName()
+ "\t 其值为:" + this.valclass.getValue());
}
}
class ValueTest{
private int value;
public synchronized void setValue(int val) {
this.value = val;
try {
Thread.sleep(4000);
}
catch (Exception e) {
e.printStackTrace();
}
this.value += val;
}
public int getValue() {
return this.value;
}
}
输出:
第一种情况:
线程名称:Thread-0 其值为:0
线程名称:Thread-1 其值为:200
第二种情况:
线程名称:Thread-0 其值为:100
线程名称:Thread-1 其值为:200
第一种情况分析:
thread0.start();
这一步会开启一个子线程,并且打印出this.valclass.getValue()
的值,这是值为0。
然后执行thread0.valclass.setValue(100);
,此时的值为100,然后主线程被阻塞4秒,方法结束后此时的值为200,最后执行thread1.start();
。
第二种情况分析:
thread0.start();
这一步会开启一个子线程,并且主线程继续往下执行语句thread0.valclass.setValue(100);
,将值设为100并且阻塞主线程4秒,然后子线程才执行到打印this.valclass.getValue()
的值,因为 getValue()方法不是同步的,所以子线程执行的时候不需要获取锁,可以直接执行非同步方法,此时打印出的值为100,等到主线程阻塞结束后,执行thread1.start();
,打印出值为200
验证代码2:
public class VerifyThread2 {
public static void main(String[] args) {
ValueTest ValueC = new ValueTest();
MyThread thread0 = new MyThread(ValueC);
MyThread thread1 = new MyThread(ValueC);
thread0.valclass.setValue(100);
thread0.start();
thread1.start();
}
}
输出:
线程名称:Thread-1 其值为:200
线程名称:Thread-0 其值为:200
分析:
thread0.valclass.setValue(100);
主线程执行到这里就被阻塞4秒,然后执行完后值为200,之后的两个子线程打印出的值都为200。
验证代码3:
public class VerifyThread3 {
public static void main(String[] args) {
ValueTest ValueC = new ValueTest();
MyThread thread0 = new MyThread(ValueC);
MyThread thread1 = new MyThread(ValueC);
thread0.start();
thread1.start();
thread0.valclass.setValue(100);
}
}
输出:
第一种情况:
线程名称:Thread-0 其值为:0
线程名称:Thread-1 其值为:0
第二种情况:
线程名称:Thread-0 其值为:0
线程名称:Thread-1 其值为:100
阻塞4秒
阻塞4秒
第三种情况:
线程名称:Thread-1 其值为:0
线程名称:Thread-0 其值为:0
阻塞4秒
第四种情况:
线程名称:Thread-1 其值为:100
线程名称:Thread-0 其值为:0
阻塞4秒
第五种情况:
线程名称:Thread-0 其值为:100
线程名称:Thread-1 其值为:100
阻塞4秒
验证代码4(getValue()方法改成同步方法):
public class VerifyThread4 {
public static void main(String[] args) {
ValueTest2 ValueC = new ValueTest2();
MyThread2 thread0 = new MyThread2(ValueC);
MyThread2 thread1 = new MyThread2(ValueC);
thread0.start();
thread1.start();
thread0.valclass.setValue(100);
}
}
class MyThread2 extends Thread{
ValueTest2 valclass;
public MyThread2(ValueTest2 valclass) {
this.valclass = valclass;
}
@Override
public void run() {
System.out.println("线程名称:" + Thread.currentThread().getName()
+ "\t 其值为:" + this.valclass.getValue());
}
}
class ValueTest2{
private int value;
public synchronized void setValue(int val) {
this.value = val;
try {
Thread.sleep(4000);
}
catch (Exception e) {
e.printStackTrace();
}
this.value += val;
}
public synchronized int getValue() {
return this.value;
}
}
输出:
第一种情况:
阻塞4秒
线程名称:Thread-0 其值为:200
线程名称:Thread-1 其值为:200
第二种情况:
阻塞4秒
线程名称:Thread-1 其值为:200
线程名称:Thread-0 其值为:200
第三种情况:
线程名称:Thread-1 其值为:0
线程名称:Thread-0 其值为:0
阻塞4秒
第四种情况:
线程名称:Thread-0 其值为:0
线程名称:Thread-1 其值为:0
阻塞4秒
第五种情况:
线程名称:Thread-0 其值为:0
阻塞4秒
线程名称:Thread-1 其值为:200
getValue()
方法改成了同步方法,所以输出的值中不会出现100。因为如果进入setValue(int val)
方法,则 ValueTest2对象的锁就被某个线程获取,其他线程都需要等待setValue(int val)
方法执行完毕,执行完毕的值必为200。
总结:
当线程A调用对象加入synchronized关键字的X方法时,A线程就获得了方法锁,更准确的讲是获得了对象锁,所以其他线程必须等待线程A执行完该同步的X方法后才能执行该X方法.但其他线程可以调用非synchronized的方法.但是也不能调用其他synchronized的方法.
为什么要这么处理呢?
假如同步方法X和Y都对变量num进行操作,线程A访问方法X,方法X未执行完,线程B访问方法Y,两个都对num进行处理,这可能会出现问题!就失去了synchronized存在的意义.
public synchronized void X(){ // do something for num }
public synchronized void Y(){ // do something for num }
网友评论