这篇文章需要探究的问题是当一个线程调用一个对象的同步方法(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 }