最近在面试中遇到很多关于多线程的问题,特别是锁的应用,现在我就来说说类锁和对象锁。
对象锁(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));
}
}
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));
}
今天的分享就到这里