Java之執行緒安全問題的3種處理方式(通過執行緒同步)
出現執行緒安全問題我們如何處理?? ==》同步原理
1.同步方法:synchronized 修飾的方法 ex:public synchronized void test(){}
弊端:方法中的所有程式碼,都只允許一個執行緒訪問。
(有一種情況:一個方法中,有一個部分程式碼不會涉及到執行緒安全問題,可以允許多個執行緒同時訪問 == 》即下面的2.同步程式碼塊)
2.同步程式碼塊 : synchronized(被加鎖的物件){ 程式碼 }
3.鎖機制Lock
①建立ReentrantLock物件
②呼叫lock方法:加鎖
{程式碼....}
③呼叫unlock方法:解鎖
注意:可把解鎖的unlock方法的呼叫放在finally{}程式碼塊中,保證一定能解鎖提醒:在同步的時候,其他程式碼都可以多個執行緒同時執行!只是被同步的程式碼不能同時執行!
ex1: 同步方法 使用synchronized 修飾方法 ==》 解決執行緒安全問題
/**
* 執行緒安全問題
* @author 鄭清
*/
public class Demo {
public static void main(String[] args) {
A a = new A();
MyThread t1 = new MyThread(a);
MyThread t2 = new MyThread(a);
t1.start();
t2.start();
}
}
class A{
private int tickets = 20;//記錄車票的數量
/*
* 在方法定義時,新增一個synchronized修飾符
* 效果:
* 使用synchronized修飾的方法就是同步方法
* 特點: 1.效率會變低
* 2.沒有執行緒安全問題了
* 原理:在方法新增synchronized之後,就相等於給當前物件(當前場景是a)加了一把鎖.
* 鎖的作用:當一個執行緒進入該方法時,先看鎖還在不在,鎖在:把鎖取走
* 在第一個執行緒還沒有結束時,第二個執行緒訪問該方法,先看鎖還在不在? 鎖不在==》等待鎖回來
* 第一個執行緒執行結束,把鎖還回去,第二個執行緒發現鎖回來了,把鎖取走,開始執行方法
*/
public synchronized void getTicket(){
if(tickets>0){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*
* 列印出來的結果有可能有重複的車票數量
* 甚至有負數,就是發生了執行緒安全問題
* 原因是:兩個執行緒同時進入了此物件的getBean方法,讀取的車票數量是另一個執行緒修改之前的值
*/
System.out.println("車票還剩: "+ (--tickets) + "張 !");
}
}
}
class MyThread extends Thread{
private A a;
public MyThread(A a) {
this.a = a;
}
public void run() {
while(true){
a.getTicket();
}
}
}
執行結果圖:(如果沒有使用synchronized 修飾方法 getTicket( ) ==》 可能就會出現下圖2執行緒安全問題)
ex2 : 同步程式碼塊 synchronized(被加鎖的物件){ 程式碼 } ==》 解決執行緒安全問題
/**
* 同步程式碼塊 :synchronized(被加鎖的物件){ 程式碼 }
* @author 鄭清
*/
public class Demo2 {
public static void main(String[] args) {
WC wc = new WC();
Person person1 = new Person(wc);
Thread t1 = new Thread(person1);
t1.setName("張三");
Person person2 = new Person(wc);
Thread t2 = new Thread(person2);
t2.setName("李四");
t1.start();
t2.start();
}
}
//上廁所
class WC{
//定義一個方法實現上廁所
public void test(){
try{
System.out.println(Thread.currentThread().getName()+" : 拿紙...");
Thread.sleep(1000);
/*
* 把上廁所的程式碼 放在 同步程式碼塊中
* 該程式碼塊中的程式碼在一個時間點只能被一個執行緒訪問,其他執行緒需要排隊等待
*/
synchronized (this) {
System.out.println(Thread.currentThread().getName()+" : 上廁所...");
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+" : 出廁所");
}
System.out.println(Thread.currentThread().getName()+" : 上完廁所,真舒服,洗個手 ... end");
}catch (Exception e) {
// TODO: handle exception
}
}
}
class Person implements Runnable{
private WC wc;
public Person(WC wc) {
super();
this.wc = wc;
}
public void run() {
wc.test();
}
}
執行結果圖: (如果不處理執行緒安全問題可能就會出現下圖2情況:張三和李四同時在一個廁所上廁所 很噁心...哈哈)
ex3 : 鎖機制Lock ==》 解決執行緒安全問題 (這個例子在ex2上修改而成的)
/**
* 使用Lock的步驟:
* 1.建立Lock實現類的物件
* 2.使用Lock物件的lock方法加鎖
* 3.使用Lock物件的unlock方法解鎖
* 注意:可把unlock方法的呼叫放在finally程式碼塊中,保證一定能解鎖
* @author 鄭清
*/
public class Demo3 {
public static void main(String[] args) {
WC wc = new WC();
//自定義執行緒步驟③:建立自定義類物件
Person person1 = new Person(wc);
Person person2 = new Person(wc);
//自定義執行緒步驟④:建立Thread類物件
Thread t1 = new Thread(person1);
Thread t2 = new Thread(person2);
//給執行緒名稱賦值
t1.setName("張三");
t2.setName("李四");
//自定義執行緒步驟⑤:啟動執行緒
t1.start();
t2.start();
}
}
// 上廁所
class WC {
// 1.建立Lock實現類的物件 注意:需在test()方法外執行,如果在test()方法裡執行,在test()方法被呼叫的時候就會被建立很多ReentrantLock物件,即出現很多鎖
ReentrantLock lock = new ReentrantLock();
// 定義一個方法實現上廁所
public void test() {
System.out.println(Thread.currentThread().getName() + " : 拿紙...");
// 2.使用Lock物件的lock方法加鎖
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + " : 上廁所...");
System.out.println(Thread.currentThread().getName() + " : 出廁所");
System.out.println(Thread.currentThread().getName() + " : 上完廁所,真舒服,洗個手 ... end");
} finally {
// 3.使用Lock物件的unlock方法解鎖
lock.unlock();
}
}
}
//自定義執行緒步驟①:建立自定義類 實現 Runnable介面
class Person implements Runnable {
private WC wc;
public Person(WC wc) {
super();
this.wc = wc;
}
//自定義執行緒步驟②:覆寫run方法
public void run() {
wc.test();
}
}
執行結果圖:(這裡注意:在lock鎖的地方 比如這個例子,圖2中 張三上廁所的同時,李四可以去拿紙,但是不能去廁所!!)
相關文章
- Java多執行緒學習(3)執行緒同步與執行緒通訊Java執行緒
- 執行緒安全處理之Threadlocal執行緒thread
- Java多執行緒中執行緒安全與鎖問題Java執行緒
- 深入JAVA執行緒安全問題Java執行緒
- 多執行緒,執行緒類三種方式,執行緒排程,執行緒同步,死鎖,執行緒間的通訊,阻塞佇列,wait和sleep區別?執行緒佇列AI
- Java之執行緒同步完成售票例項的6種方式Java執行緒
- Java多執行緒之執行緒同步【synchronized、Lock、volatitle】Java執行緒synchronized
- Java併發程式設計之執行緒安全、執行緒通訊Java程式設計執行緒
- Map實現執行緒安全的3種方式執行緒
- java的執行緒、建立執行緒的 3 種方式、靜態代理模式、Lambda表示式簡化執行緒Java執行緒模式
- 【java】【多執行緒】建立執行緒的兩種常用方式(2)Java執行緒
- 【多執行緒總結(二)-執行緒安全與執行緒同步】執行緒
- JAVA多執行緒詳解(3)執行緒同步和鎖Java執行緒
- Java之自定義執行緒的2種方式Java執行緒
- Java多執行緒-執行緒通訊Java執行緒
- Java執行緒(九):Condition-執行緒通訊更高效的方式Java執行緒
- 【Java多執行緒】執行緒安全的集合Java執行緒
- 3種方式實現python多執行緒併發處理Python執行緒
- 執行緒、開啟執行緒的兩種方式、執行緒下的Join方法、守護執行緒執行緒
- Java 執行緒安全問題的本質Java執行緒
- Java多執行緒之—Synchronized方式和CAS方式實現執行緒安全效能對比Java執行緒synchronized
- QT執行緒同步與非同步處理QT執行緒非同步
- 多執行緒系列之 執行緒安全執行緒
- iOS 多執行緒之執行緒安全iOS執行緒
- 多執行緒Demo學習(執行緒的同步,簡單的執行緒通訊)執行緒
- Java之執行緒通訊Java執行緒
- java--執行緒池--建立執行緒池的幾種方式與執行緒池操作詳解Java執行緒
- Java多執行緒之執行緒中止Java執行緒
- 03 執行緒安全問題執行緒
- SimpleDateFormat 執行緒安全問題ORM執行緒
- Java多執行緒面試高配問題---多執行緒(3)🧵Java執行緒面試
- ArrayList 的執行緒安全問題執行緒
- iOS多執行緒全套:執行緒生命週期,多執行緒的四種解決方案,執行緒安全問題,GCD的使用,NSOperation的使用iOS執行緒GC
- 多執行緒,你覺得你安全了?(執行緒安全問題)執行緒
- java 多執行緒之使用 interrupt 停止執行緒的幾種方法Java執行緒
- java各種集合的執行緒安全Java執行緒
- C++執行緒同步的四種方式(Windows)C++執行緒Windows
- iOS多執行緒安全-13種執行緒鎖?iOS執行緒