类锁和对象锁的详解

来源:互联网 发布:网络骗局如何报警 编辑:程序博客网 时间:2024/06/05 06:49

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

对象锁(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));    }


今天的分享就到这里




原创粉丝点击