一、解決線程安全總體可分為兩大類:
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關鍵字