这篇文章需要探究的问题是当一个线程调用一个对象的同步方法(synchronized修饰)时,其获得的是对象锁(其他线程无法访问该对象的所有方法),还是获得的是对象方法的锁(其他线程只是无法访问该方法而已).
也就是说,有一个类有三个方法,其中两个为同步方法.另一个为非同步方法.
当有两个线程Thread0和Thread1,Thread0在调用fun1()时,可以确定的是Thread1也是无法调用fun1()的.
但是Thread1能不能够调用fun2和fun3呢?
这就是本文需要探究的问题.
class test{
public synchronized void fun1()
{}
public void fun2()
{}
public synchronized void fun3()
{}
}
package myThread;
public class TestThread {
public static void main(String[] args) {
// TODO Auto-generated method stub
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;
}
public void run() {
System.out.println("the thread name is :" + Thread.currentThread().getName()
+ "\t the value is :" + this.valclass.getValue());
}
}
class ValueTest{
private int value;
public synchronized void setValue(int val) {
this.value = val;
try {
Thread.sleep(1000);
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
this.value += val;
}
public int getValue() {
return this.value;
}
}
类ValueTest创建了一个同步方法setValue(int val) 和一个非同步方法getValue().
在setValue(int val)中,先根据传入的参数设置value值,然后睡眠1000ms,之后再累加传入的值.因此设置了两次.
public synchronized void setValue(int val) {
this.value = val;
try {
Thread.sleep(1000);
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
主函数中创建了两个线程,并且线程1调用setValue(100)设在value值.
ValueTest ValueC = new ValueTest();
MyThread thread0 = new MyThread(ValueC);
MyThread thread1 = new MyThread(ValueC);
thread0.start();
thread1.start();
thread0.valclass.setValue(100);
线程执行程序run输出当前线程的名称和value值.
public void run() {
System.out.println("the thread name is :" + Thread.currentThread().getName()
+ "\t the value is :" + this.valclass.getValue());
}
输出为:
the thread name is :Thread-0 the value is :100
the thread name is :Thread-1 the value is :100
当将getValue设置为同步方法后
public synchronized int getValue() {
return this.value;
}
输出为,此时线程0的value更改为200.
the thread name is :Thread-0 the value is :200
the thread name is :Thread-1 the value is :200
分析程序
第一种情况下,getValue() 不是同步方法,当Thread-0调用setValue(100)后,value值设置为100.之后线程1进入休眠状态1000ms.Thread-1获得运行权,执行run最后两者都打印value的值100;
第二种情况getValue() 是同步方法,当Thread-0调用setValue(100)后,
value值设置为100.两个线程的run中都等待setValue(100)执行完后才能执行getValue.所以两个线程打印的值都为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 }