一、模拟线程不安全场景。
public class MyRunnable implements Runnable { private int a = 100; //共享的数据 @Override public void run() { while (true) { if (a > 0) { //多个MyRunnable线程同时访问共享数据,结果不是想要的。导致线程不安全 System.out.println(a); a--; } else { break; } } } }
public static void main(String[] args) { MyRunnable myRunnable = new MyRunnable(); new Thread(myRunnable).start(); new Thread(myRunnable).start(); new Thread(myRunnable).start(); }
二、使用对象监视器解决问题,使其安全。将线程类修改如下。
public class MyRunnable implements Runnable { private int a = 100; //共享的数据 Object obj = new Object(); @Override public void run() { while (true) { //使用了一个锁对象。这种锁又叫:同步锁,对象锁,对象监视器。 synchronized (obj) { if (a > 0) { System.out.println(a); a--; } else { break; } } } } }
对象锁
优点:保证了线程安全,同一时间只能有一个线程执行共享数据。
缺点:程序频繁的判断锁、获取锁和释放锁,程序的效率会降低。
三、使用同步方法解决问题,其实思想和上面解决方法一直。将线程类修改如下。
public class MyRunnable implements Runnable { private int a = 100; //共享的数据 Object obj = new Object(); @Override public void run() { while (true) { boolean bo = inA(); if (!bo) break; } } //使用的也是对象锁,锁对象就是this public synchronized boolean inA(){ if (a > 0) { System.out.println(a); a--; return true; } else { return false; } } }
三、使用静态同步方法解决问题,与同步方法的区别是锁对象不同。将线程类修改如下。
public class MyRunnable implements Runnable { private static int a = 100; //共享的数据 Object obj = new Object(); @Override public void run() { while (true) { boolean bo = inA(); if (!bo) break; } } //使用的也是对象锁,锁对象就是奔本类的class属性->class文件对象(反射机制)。MyRunnable.class public static synchronized boolean inA(){ if (a > 0) { System.out.println(a); a--; return true; } else { return false; } } }
使用Lock锁解决线程安全问题,将线程类修改如下。
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MyRunnable implements Runnable { private static int a = 100; //共享的数据 /* 1、创建ReentrantLock对象。 2、在可能出现线程安全问题代码【前】调用【lock()】方法获取锁 3、在可能出现线程安全问题代码【后】调用【unlock()】方法释放锁 */ Lock lock = new ReentrantLock(); // @Override public void run() { while (true) { lock.lock(); try { if (a > 0) { System.out.println(a); a--; } else { break; } } catch (Exception e) { } finally { //无论是否异常,都需要是否锁 lock.unlock(); } } } }