从此不怕Synchronized锁

Synchronized的使用

​ Synchronized是通过监视器保证线程同步从而保证线程安全。但是Synchronized锁可以锁对象和锁类,并会产生不同的效果,通过下面的案例彻底理解Synchronized锁的使用方式。

即:

对于普通的同步方法,锁是当前实例对象

对于静态同步方法,锁是该类

对于同步方法块,锁是Synchronized括号里面配置的对象。

下面通过代码具体分析几种情况。要想了解并发情况,首先我们必须知道,类信息、实例对象分别存放在什么位置。类的信息,包括静态变量都是存放在方法区中;而实例对象,包括类的成员变量,是存放在堆中。

1. 成员变量+普通同步方法+锁 public class SynDemo implements Runnable { private int sum = 0; @Override public void run() { add(); } public synchronized void add() { for (int i = 0; i < 1000; i++) { sum++; } } public static void main(String[] args) throws InterruptedException { SynDemo sync01 = new SynDemo(); Thread thread1 = new Thread(sync01); Thread thread2 = new Thread(sync01); thread1.start(); thread2.start(); thread1.join(); //等待线程执行完 thread2.join(); //等待线程执行完 System.out.println(sync01.sum); System.out.println(new SynDemo().sum); } } result: 2000 0 public class SynDemo implements Runnable { private int sum = 0; @Override public void run() { add(); } public synchronized void add() { for (int i = 0; i < 1000; i++) { sum++; } } public static void main(String[] args) throws InterruptedException { SynDemo sync01 = new SynDemo(); SynDemo sync02 = new SynDemo(); Thread thread1 = new Thread(sync01); Thread thread2 = new Thread(sync02); thread1.start(); thread2.start(); thread1.join(); //等待线程执行完 thread2.join(); //等待线程执行完 System.out.println(sync01.sum); System.out.println(sync02.sum); } } result: 1000 1000 0

分析:

​ 理解了这两个demo再去理解同步代码块下的多线程安全问题,将会达到事半功倍的效果。上面两个demo主要是想表达,成员变量和类的实例化对象一样,都是在堆中创建,每次new对象,都会在堆中产生一个新的对象。所以第一个demo中,当在线程同步的情况下,两个线程去操作同一个对象,最后的结果是2000;而第二个demo中,两个线程去操作两个实例化对象,所以每个对象的成员变量sum为1000。因此我们也可以发现,其实在第一个demo中才会有线程安全问题,在第二个demo中是不存在线程安全问题的,有疑问可以去掉锁验证一下。通过这个例子也可以去理解为什么sping中多例是线程安全的。

2. 成员变量+同步代码块+对象锁 public class SynDemo implements Runnable { private int sum = 0; @Override public void run() { add(); } private void add() { synchronized (this) { for (int i = 0; i < 1000; i++) { sum++; } } } public static void main(String[] args) throws InterruptedException { SynDemo sync01 = new SynDemo(); Thread thread1 = new Thread(sync01); Thread thread2 = new Thread(sync01); thread1.start(); thread2.start(); thread1.join(); //等待线程执行完 thread2.join(); //等待线程执行完 System.out.println(sync01.sum); System.out.println(new SynDemo().sum); } } result: 2000 0 public class SynDemo implements Runnable { private int sum = 0; @Override public void run() { add(); } private void add() { synchronized (this) { for (int i = 0; i < 1000; i++) { sum++; } } } public static void main(String[] args) throws InterruptedException { SynDemo sync01 = new SynDemo(); SynDemo sync02 = new SynDemo(); Thread thread1 = new Thread(sync01); Thread thread2 = new Thread(sync02); thread1.start(); thread2.start(); thread1.join(); //等待线程执行完 thread2.join(); //等待线程执行完 System.out.println(sync01.sum); System.out.println(sync02.sum); System.out.println(new SynDemo().sum); } } result: 1000 1000 0

分析:

​ 同案例1一样,Demo1为两个线程执行一个实例化对象,但是加了Synchronized对象锁,因此实现了同步,保证线程安全。Demo2为两个线程执行两个实例化对象,各自利用各自的成员变量sum,因此不会产生并发安全问题。

3. 成员变量+同步代码块+类锁 public class SynDemo implements Runnable { private int sum = 0; @Override public void run() { add(); } private void add() { synchronized (SynDemo.class) { for (int i = 0; i < 1000; i++) { sum++; } } } public static void main(String[] args) throws InterruptedException { SynDemo sync01 = new SynDemo(); Thread thread1 = new Thread(sync01); Thread thread2 = new Thread(sync01); thread1.start(); thread2.start(); thread1.join(); //等待线程执行完 thread2.join(); //等待线程执行完 System.out.println(sync01.sum); System.out.println(new SynDemo().sum); } } result: 2000 0 public class SynDemo implements Runnable { private int sum = 0; @Override public void run() { add(); } private void add() { synchronized (SynDemo.class) { for (int i = 0; i < 1000; i++) { sum++; } } } public static void main(String[] args) throws InterruptedException { SynDemo sync01 = new SynDemo(); SynDemo sync02 = new SynDemo(); Thread thread1 = new Thread(sync01); Thread thread2 = new Thread(sync02); thread1.start(); thread2.start(); thread1.join(); //等待线程执行完 thread2.join(); //等待线程执行完 System.out.println(sync01.sum); System.out.println(sync02.sum); System.out.println(new SynDemo().sum); } } result: 1000 1000 0

分析:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzpzd.html