一、解决线程安全总体可分为两大类:
1.使用synchronized关键字(可修饰代码块或方法)
(1)使用synchronized关键字修饰代码块
public class ThreadDemo { public static void main(String[] args) { ThreadSafe1 thread = new ThreadSafe1(); Thread t1 = new Thread(thread); Thread t2 = new Thread(thread); Thread t3 = new Thread(thread); t1.setName("窗口一"); t2.setName("窗口二"); t3.setName("窗口三"); t1.start(); t2.start(); t3.start(); } } class ThreadSafe1 implements Runnable{ //定义车票的数量 private int ticket = 100; @Override public void run() { while(true) { synchronized(ThreadSafe1.class) { //同步监视器为ThreadSafe1.class,它只加载一次,是唯一的,该同步代码块里包含着共享数据的操作 if(ticket > 0) { System.out.println(Thread.currentThread().getName()+":"+"出售第"+ticket+"张车票"); //车票数量减一 ticket--; }else { break; } } } } }
(2)使用synchronized关键字修饰方法
public class ThreadDemo { public static void main(String[] args) { ThreadSafe2 thread = new ThreadSafe2(); Thread t1 = new Thread(thread); Thread t2 = new Thread(thread); Thread t3 = new Thread(thread); t1.setName("窗口一"); t2.setName("窗口二"); t3.setName("窗口三"); t1.start(); t2.start(); t3.start(); } } class ThreadSafe2 implements Runnable{ //定义车票的数量 private int ticket = 100; @Override public void run() { while(true) { //调用窗口售票方法 sale(); if(ticket == 0) { break; } } } //实现窗口售票 public synchronized void sale() { //该方法的同步监视器为ThreadSafe2的对象,它是唯一的,这里面也存放着对共享数据的操作 if(ticket > 0) { System.out.println(Thread.currentThread().getName()+":"+"出售第"+ticket+"张车票"); //车票数量减一 ticket--; } } }
2.使用Lock锁方式解决线程安全问题
public class ThreadDemo { public static void main(String[] args) { ThreadSafe3 thread = new ThreadSafe3(); Thread t1 = new Thread(thread); Thread t2 = new Thread(thread); Thread t3 = new Thread(thread); t1.setName("窗口一"); t2.setName("窗口二"); t3.setName("窗口三"); t1.start(); t2.start(); t3.start(); } } class ThreadSafe3 implements Runnable{ //定义车票的数量 private int ticket = 100; private ReentrantLock lock = new ReentrantLock(); @Override public void run() { while(true) { try { lock.lock(); //对对操作共享数据的代码进行加锁 //进行线程休眠,增加其他线程调用的机会 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if(ticket > 0) { System.out.println(Thread.currentThread().getName()+":"+"出售第"+ticket+"张车票"); //车票数量减一 ticket--; }else { break; } }finally { lock.unlock(); //进行解锁 } } } }
二、synchronized关键字与Lock锁方式的区别
(1)两者都可以解决线程安全问题
(2)synchronized关键字既可以修饰代码块又可以修饰方法;而Lock锁方式只可以修饰代码块
(3)synchronied关键字修饰的代码块或方法在运行结束后,会自动释放锁;而Lock锁方式需手动为代码块加锁并释放锁
(4)从性能上,Lock锁方式优于synchronized关键字