zoukankan      html  css  js  c++  java
  • 多线程的对象锁和类锁

        今天面试官问了一个问题,如果在一个类中的普通方法加上synchronized 关键字,两个线程可以同步方法这个方法吗?为什么

    当时回答是不可以同步,然后面试官确认我说一定吗?当时就知道回答错了。

        现在实现了下,原来是类锁和对象锁的区别所在,也算是普及了下相关知识吧。

    类锁:就是在方法前面加上 static synchronized或者方法里面 synchronized(MainThings.class) 这两个写法,那么这是一个类锁。

    对象锁:就是在方法前面加上synchronized或者方法里面 synchronized(this) 这两个写法,那么这是一个类锁。

    结论:如果是对象锁的话,两个线程可以同时访问同一个方法。

              如果是类锁的话,两个线程是不可以同时访问同一个方法,当前线程会将另外一个线程阻塞起来,等当前线程处理完了释放了当前锁后才可以进来。

    原因:对象锁-》面对每一个对象来说,都有各自的锁,每个线程访问不同对象时都可以拥有自己的锁,所以不会造成这个线程的对象被另一个对象上锁。

              类锁-》对每个线程来说,只有一把锁,谁先拥有这把锁,谁先访问,其他线程阻塞,等当前访问完了的线程释放锁后,其他线程才可以访问。

    public class DoThing1 implements Runnable {

    private MainThings mainThings;

    public DoThing1(MainThings mainThings)
    {
    this.mainThings=mainThings;
    }

    @Override
    public void run() {
    System.out.println(Thread.currentThread().getName()+" DoThing1 is begin");
    mainThings.test();

    }

    }

    public class DoThing2 implements Runnable {

    MainThings mainThings;

    public DoThing2( MainThings mainThings)
    {
    this.mainThings=mainThings;
    }

    @Override
    public void run() {
    System.out.println(Thread.currentThread().getName()+" DoThing2 is begin");
    mainThings.test();

    }

    }

    public class DoThing2 implements Runnable {

    MainThings mainThings;

    public DoThing2( MainThings mainThings)
    {
    this.mainThings=mainThings;
    }

    @Override
    public void run() {
    System.out.println(Thread.currentThread().getName()+" DoThing2 is begin");
    mainThings.test();

    }

    }

    主类:

    public class MainThings {

    /**
    * 对象锁
    */
    public synchronized void test() {

    System.out.println("this is"+ Thread.currentThread().getName()+" entry");

    System.out.println("this is"+ Thread.currentThread().getName()+" out");



    }

    /**
    * @param args
    */
    public static void main(String[] args) {
    // TODO Auto-generated method stub

    MainThings mainThings=new MainThings();
    MainThings mainThings2=new MainThings();
    DoThing1 do1=new DoThing1(mainThings);
    DoThing2 do2=new DoThing2(mainThings2);
    Thread t1=new Thread(do1);
    Thread t2=new Thread(do2);

    t1.start();
    t2.start();

    }

    }

    执行结果:

    Thread-1 DoThing2 is begin
    Thread-0 DoThing1 is begin
    this isThread-1 entry
    this isThread-0 entry
    this isThread-0 out
    this isThread-1 out

    类锁:

    public static synchronized void test() {

    System.out.println("this is"+ Thread.currentThread().getName()+" entry");

    System.out.println("this is"+ Thread.currentThread().getName()+" out");



    }

    /**
    * @param args
    */
    public static void main(String[] args) {

    // TODO Auto-generated method stub

    MainThings mainThings=new MainThings();
    MainThings mainThings2=new MainThings();
    DoThing1 do1=new DoThing1(mainThings);
    DoThing2 do2=new DoThing2(mainThings2);
    Thread t1=new Thread(do1);
    Thread t2=new Thread(do2);

    t1.start();
    t2.start();

    }

    执行结果:

    Thread-0 DoThing1 is begin
    this isThread-0 entry
    this isThread-0 out
    Thread-1 DoThing2 is begin
    this isThread-1 entry
    this isThread-1 out

    PS:转载知乎上面大牛的对类锁和对象锁的解释:

    作者:beralee
    链接:https://www.zhihu.com/question/19708552/answer/12719903
    来源:知乎
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    要明白两个问题,1.锁的对象是谁,2.谁持有了锁。
    假设方法A和B是在同一个类Test中的两个方法。

    Test t=new Test();
    t.methodB();

    这个时候,methodB方法被调用时,因为加了synchronized ,需要先获得一个锁,这个锁的对象应该是t,也就是当前的这个Test类的实例,而获得锁的东西是线程,也就是说当前线程拿到了t的锁(而不是你说的B方法获得锁),这个时候B方法内调用methodA,因为A也加了synchronized,也需要获得一个锁,因为A和B都是Test类中的方法,所以当前线程要获得的锁的对象也是t。由于当前线程在执行B方法时已经持有了t对象的锁,因此这时候调用methodA是没有任何影响的,相当于方法A上没有加synchronized。

    另一种情况:假设现在有两个Test类
    Test t1=new Test();
    Test t2=new Test();
    t1.methodB();//此时当前线程持有了t1对象的锁
    t2.methodB();//此时当前线程也持有了t2对象的锁
    当前线程持有了两把锁,锁的对象分别是两个不同的Test类的实例t1和t2,互相没有影响。

    再一种情况:假设在多线程环境下,两个线程都可以访问Test t=new Test();
    此时假设thread1里调用t.methodB();同时thread2里调用t.methodB()

    这时假设thread1先抢到t对象的锁,那么thread2需要等待thread1释放t对象的锁才可以执行B方法。
    结果像这样:
    thread1获得t的锁--thread1执行methodB--thread1执行methodA--释放t的锁---thread2获得t的锁--thread2执行methodB--thread2执行methodA--释放t的锁。

    synchronized还有很多种使用方法,但只有明白是那条线程获得哪个对象的锁,就很容易明白了
     
     
  • 相关阅读:
    银行卡和手机号占位符
    防京东进度尺的金额
    圆的进度条
    HMTL5滑动块研究
    自动生成验证码
    HTML5语义化
    (转)C++中使用C代码
    (转)四旋翼飞行器基本知识
    如何将.jpg图片 转换成.eps 格式图片
    HDOJ 1196 Lowest Bit
  • 原文地址:https://www.cnblogs.com/xlh-2014/p/8589205.html
Copyright © 2011-2022 走看看