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