Demo1为两个线程执行一个实例化对象,会产生并发安全问题,但是加了同步类锁(可以理解为锁的级别比对象锁更高),当然也可以实现并发同步,保证线程安全。而Demo2同样实例化两个对象,各自操作各自的成员变量sum,也不会产生线程安全问题。
4. 静态变量+普通方法+锁 public class SynDemo implements Runnable { private static int sum = 0; @Override public void run() { add(); } private 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(sum); } } result: 2000 public class SynDemo implements Runnable { private static int sum = 0; @Override public void run() { add(); } private 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(sum); } } 输出结果不确定(存在线程安全问题)分析:
从案例4我们要注意,由成员变量换成静态变量,而上面已经讲过,静态变量存放在方法区中,所有实例化对象共享一份。再看Demo1,两个线程执行同一个实例化对象,然后添加的是对象锁,因此该对象锁能锁住该实例化对象,实现同步,保证线程安全。
Demo2是两个线程执行两个实例化对象,添加的是对象锁,相当于各自的对象锁锁住各自的对象,而静态变量是类变量,存放在方法区中而不是堆中,此情况对象锁并不能保证线程同步,因此会产生线程安全问题。
5. 静态变量+静态方法+锁 public class SynDemo implements Runnable { private static int sum = 0; @Override public void run() { add(); } static 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(sum); } } result: 2000 public class SynDemo implements Runnable { private static int sum = 0; @Override public void run() { add(); } static 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(sum); } } result: 2000分析:
该案例相比案例4,锁由对象锁换成类锁,对于Demo1,两个线程操作一个对象,毫无疑问会使其同步。而Demo2,两个线程执行两个实例化对象,由于使用的是类锁,也会使线程同步,保证线程安全。
6. 静态变量+同步代码块+对象锁 public class SynDemo implements Runnable { private static 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(sum); } } result: 2000 public class SynDemo implements Runnable { private static 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(sum); } } 输出结果不确定(存在线程安全问题)