类锁和对象锁的详解

最近在面试中遇到很多关于多线程的问题,特别是锁的应用,现在我就来说说类锁和对象锁。

对象锁(synchronized method{})和类锁(static sychronized method{})的区别

对象锁也叫实例锁,对应synchronized关键字,当多个线程访问多个实例时,它们互不干扰,每个对象都拥有自己的锁,如果是单例模式下,那么就是变成和类锁一样的功能。

对象锁防止在同一个时刻多个线程访问同一个对象的synchronized块。如果不是同一个对象就没有这样子的限制。

类锁对应的关键字是static sychronized,是一个全局锁,无论多少个对象否共享同一个锁(也可以锁定在该类的class上或者是classloader对象上),同样是保障同一个时刻多个线程同时访问同一个synchronized块,当一个线程在访问时,其他的线程等待。


代码样例

我们就拿账户存钱取钱的情景来模拟,以下是使用对象锁

Account类

public class Account {
    /**
     * 账户类
     */
    private static volatile int count = 100;

    public synchronized void add(int m){
        String name = Thread.currentThread().getName();
        System.out.println("对象锁添加" + m + "钱," + name + "添加后:" + (count+=m));
    }

    public synchronized void mul(int m){
        String name = Thread.currentThread().getName();
        System.out.println("对象锁减少" + m + "钱," + name + "消费后:" + (count-=m));
    }
}


Main类

public static void main(String[] args) {
          CyclicBarrier barrier = new CyclicBarrier(4);
          Account suo = new Account();
          Account suo1 = new Account();
          for (int i=0;i<4;i++){
              int n=i+1;
              int j=n*3;
              new Thread(new Runnable() {
                  @Override
                  public void run() {
                      try {
                          Thread.sleep(1000*(new Random().nextInt(8)));
                          System.out.println("线程"+n+"准备好了");
                          barrier.await();
                          if(n==1||n==3)
                              suo.add(j);//1,3
                          else
                              suo.mul(j);//2,4
                      } catch (Exception e) {
                          e.printStackTrace();
                      }

                  }
              },"线程"+i).start();
}
使用CyclicBarrier类让四个子线程都准备好了之后就开始对账户进行操作,1、3线程执行添加,2、4执行减少可以看到线程执行是同步的,多个线程没有在同一时刻去访问,如果在2、4线程的时候,执行suo1对象访问mul()方法

 if(n==1||n==3)
     suo.add(j);//1,3
 else
     suo1.mul(j);//2,4

可以看到结果,线程的执行不是同步的,而是异步的,所以如果想要用对象锁进行同步操作,就必须锁定同一个对象

接着继续看类锁,当多个线程执行同一个对象的加减操作时

public class Account {
    /**
     * 账户类
     */
    private static int count = 100;

    public static synchronized void add(int m){
        String name = Thread.currentThread().getName();
        System.out.println("类锁添加" + m + "钱," + name + "添加后:" + (count+=m));
    }

    public static synchronized void mul(int m){
        String name = Thread.currentThread().getName();
        System.out.println("类锁减少" + m + "钱," + name + "消费后:" + (count-=m));
    }
}
运行结果


从结果中也可以看出运行是同步操作的,如果同上面对象锁一样是多个线程访问多个对象操作加减方法,运行结果如下


从结果中仍然可以看出,类锁无论是访问同一个对象的synchronized块还是多个对象的,仍然是同步操作的。


总结:

1.类锁是对静态方法使用synchronized关键字后,无论是多线程访问单个对象还是多个对象的sychronized块,都是同步的。

2.对象锁是实例方法使用synchronized关键字后,如果是多个线程访问同个对象的sychronized块,才是同步的,但是访问不同对象的话就是不同步的。

3.类锁和对象锁是两种不同的锁,可以同时使用,但是注意类锁不要嵌套使用,这样子容易发生死锁。


类锁和对象锁两种使用的方式

类锁

1.代码块的方式

 public void add(int m){
        synchronized (Account.class){
            String name = Thread.currentThread().getName();
            System.out.println("类锁添加" + m + "钱," + name + "添加后:" + (count+=m));
        }
    }

2.方法锁方式

 public static synchronized void add(int m){
        String name = Thread.currentThread().getName();
        System.out.println("类锁添加" + m + "钱," + name + "添加后:" + (count+=m));
    }


对象锁

1.代码块的方式

 public void add(int m){
        synchronized(this){
            String name = Thread.currentThread().getName();
            System.out.println("对象锁添加" + m + "钱," + name + "添加后:" + (count+=m));
        }
    }

2.方法锁的方式

 public synchronized void add(int m){
        String name = Thread.currentThread().getName();
        System.out.println("对象锁添加" + m + "钱," + name + "添加后:" + (count+=m));
    }


今天的分享就到这里




  • 28
    点赞
  • 76
    收藏
    觉得还不错? 一键收藏
  • 12
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值