美文网首页
从程序分析线程获得的是对象锁还是对象的方法锁?

从程序分析线程获得的是对象锁还是对象的方法锁?

作者: hswwjp | 来源:发表于2018-12-26 18:37 被阅读4次

原文链接:
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 }

相关文章

  • 从程序分析线程获得的是对象锁还是对象的方法锁?

    原文链接:https://blog.csdn.net/u011676300/article/details/790...

  • Synchronized总结

    线程状态分析图 Synchronized的两种用法 对象锁:包括方法锁(默认对象锁为this当前实例对象)和同步代...

  • 方法锁、对象锁和类锁区别

    方法锁、对象锁和类锁区别 引言:结合synchronized进行分析。 synchronized用来处理多个线程同...

  • 【高并发】2、多线程中的锁

    一、多线程中的锁 在多线程中,锁就是要实现线程对资源的访问控制。从程序的角度来看,锁就是一个对象,这个对象需要完成...

  • 锁对象的改变

    在前面学习完多线程的synchronized对象锁之后,不禁思考到,如果当某一线程获得某对象的对象锁后,在其内部锁...

  • 线程运用---等待通知的范式wait()、notify()

    1.等待线程获取到对象的锁,调用wait()方法,放弃锁,进入等待队列2.通知线程获取到对象的锁,调用对象的not...

  • 同步阻塞

    当一个线程调用Lock对象的acquire()方法获得锁时,这把锁就进入“locked”状态。因为每次只有一个线程...

  • Python的锁源码剖析

    Lock 原始锁: 实现原始锁对象的类。一旦一个线程获得一个锁,会阻塞随后尝试获得锁的线程,直到它被释放;任何线程...

  • java sleep 与 wait

    sleep 是Thread类方法,表示线程等待一定时间,不释放对象锁。 wait是Object的方法,释放对象锁,...

  • synchornized学习笔记

    1.对象锁示例同步代码块锁 两个线程同时访问一个方法 输出结果为: 2.对象锁示例普通方法锁 两个线程同时访...

网友评论

      本文标题:从程序分析线程获得的是对象锁还是对象的方法锁?

      本文链接:https://www.haomeiwen.com/subject/iuzclqtx.html