大佬的理解-> Java多線程(三)--synchronized關鍵字詳情 大佬的理解-> Java多線程(三)--synchronized關鍵字續 1、問題引入 買票問題 1.1 通過繼承Thread買票 繼承Thread買票案例 /* 模擬網路購票,多線程資源共用問題,繼承Thread方式; 結 ...
大佬的理解-> Java多線程(三)--synchronized關鍵字詳情
大佬的理解-> Java多線程(三)--synchronized關鍵字續
1、問題引入
買票問題
1.1 通過繼承Thread買票
繼承Thread買票案例
/*
模擬網路購票,多線程資源共用問題,繼承Thread方式;
結論:此種方式,不存在資源共用,通過創建對象啟動的線程,每個對象都有各自的屬性值
*/
public class MyThreadTicket extends Thread{
//總票數
private int remainSite = 100;
//搶到的座位號
private int buySite = 0;
@Override
public void run() {
//模擬迴圈搶票
while(true){
//判斷餘票是否充足,如果不足,結束
if(remainSite <= 0){
break;
}
//更改強股票數據
buySite++;
remainSite--;
//模擬網路延遲
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"買到第"+buySite+"張票,剩餘"+remainSite+"張票");
}
}
public static void main(String[] args) {
//模擬三人同事搶票
MyThreadTicket threadTicket1 = new MyThreadTicket();
threadTicket1.setName("豬八戒");
MyThreadTicket threadTicket2 = new MyThreadTicket();
threadTicket2.setName("沙和尚");
MyThreadTicket threadTicket3 = new MyThreadTicket();
threadTicket3.setName("孫猴子");
System.out.println("---搶票開始---");
threadTicket1.start();
threadTicket2.start();
threadTicket3.start();
}
}
運行結果
---搶票開始---
豬八戒買到第1張票,剩餘99張票
孫猴子買到第1張票,剩餘99張票
沙和尚買到第1張票,剩餘99張票
孫猴子買到第2張票,剩餘98張票
豬八戒買到第2張票,剩餘98張票
沙和尚買到第2張票,剩餘98張票
孫猴子買到第3張票,剩餘97張票
沙和尚買到第3張票,剩餘97張票
豬八戒買到第3張票,剩餘97張票
豬八戒買到第4張票,剩餘96張票
沙和尚買到第4張票,剩餘96張票
孫猴子買到第4張票,剩餘96張票
孫猴子買到第5張票,剩餘95張票
......
孫猴子買到第99張票,剩餘1張票
豬八戒買到第99張票,剩餘1張票
沙和尚買到第99張票,剩餘1張票
孫猴子買到第100張票,剩餘0張票
豬八戒買到第100張票,剩餘0張票
沙和尚買到第100張票,剩餘0張票
出現的問題
每個人都買了100張票,沒有共用數據;
1.2 通過實現Runnable介面買票
實現Runnable介面案例
/*
模擬網路購票,實現Runnable方法
*/
public class MyRunnableTicket0 implements Runnable{
//總票數
private int remainSite = 100;
//搶到的座位號
private int buySite = 0;
@Override
public void run() {
//模擬迴圈搶票
while(true){
//判斷餘票是否充足,如果不足,結束
if (remainSite <= 0) {
break;
}
//更改強股票數據
buySite++;
remainSite--;
//模擬網路延遲
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "買到第" + buySite + "張票,剩餘" + remainSite + "張票");
}
}
public static void main(String[] args) {
//創建三個子線程
MyRunnableTicket0 runnableTicket = new MyRunnableTicket0();
Thread thread1 = new Thread(runnableTicket,"哪吒");
Thread thread2 = new Thread(runnableTicket,"金吒");
Thread thread3 = new Thread(runnableTicket,"木吒");
thread1.start();
thread2.start();
thread3.start();
}
}
運行結果
木吒買到第96張票,剩餘4張票
哪吒買到第96張票,剩餘4張票
金吒買到第96張票,剩餘4張票
木吒買到第99張票,剩餘1張票
哪吒買到第99張票,剩餘1張票
金吒買到第99張票,剩餘1張票
木吒買到第100張票,剩餘0張票
出現的問題
共用了數據,但是出現了漏票,和幾個人買同一張票的情況;
2、解決方法
通過synchronized同步鎖來進行同步,使同一時間只有一個人在買票;
2.1 同步代碼塊
同步代碼塊案例
/*
模擬網路購票,實現Runnable方法
同步代碼塊方法
*/
public class MyRunnableTicket implements Runnable{
//總票數
private int remainSite = 100;
//搶到的座位號
private int buySite = 0;
//同步代碼塊
@Override
public void run() {
//模擬迴圈搶票
while(true){
//同步代碼快
synchronized (this) {
//判斷餘票是否充足,如果不足,結束
if (remainSite <= 0) {
break;
}
//更改強股票數據
buySite++;
remainSite--;
//模擬網路延遲
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "買到第" + buySite + "張票,剩餘" + remainSite + "張票");
}
}
}
public static void main(String[] args) {
//創建三個子線程
MyRunnableTicket runnableTicket = new MyRunnableTicket();
Thread thread1 = new Thread(runnableTicket,"哪吒");
Thread thread2 = new Thread(runnableTicket,"金吒");
Thread thread3 = new Thread(runnableTicket,"木吒");
thread1.start();
thread2.start();
thread3.start();
}
}
運行結果
哪吒買到第1張票,剩餘99張票
哪吒買到第2張票,剩餘98張票
哪吒買到第3張票,剩餘97張票
哪吒買到第4張票,剩餘96張票
哪吒買到第5張票,剩餘95張票
......
金吒買到第96張票,剩餘4張票
金吒買到第97張票,剩餘3張票
金吒買到第98張票,剩餘2張票
金吒買到第99張票,剩餘1張票
金吒買到第100張票,剩餘0張票
可以正常買票,問題解決;
2.2 同步方法
同步方法案例
/*
模擬網路購票,實現Runnable方法
同步方法
*/
public class MyRunnableTicket implements Runnable{
//總票數
private int remainSite = 100;
//搶到的座位號
private int buySite = 0;
@Override
public void run() {
//模擬迴圈搶票
while(remainSite > 0){
//調用同步購買方法
buyTicket();
//模擬網路延遲
try {
TimeUnit.MILLISECONDS.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/*
同步方法
增加同步鎖,限制多線程場景下,只允許一個線程執行當前方法,確保票數修改正確
*/
public synchronized void buyTicket(){
//判斷餘票是否充足,如果不足,結束
if(remainSite <= 0){
return;
}
//更改強股票數據
buySite++;
remainSite--;
System.out.println(Thread.currentThread().getName()+"買到第"+buySite+"張票,剩餘"+remainSite+"張票");
}
運行結果
哪吒買到第1張票,剩餘99張票
哪吒買到第2張票,剩餘98張票
哪吒買到第3張票,剩餘97張票
哪吒買到第4張票,剩餘96張票
哪吒買到第5張票,剩餘95張票
......
金吒買到第96張票,剩餘4張票
金吒買到第97張票,剩餘3張票
金吒買到第98張票,剩餘2張票
金吒買到第99張票,剩餘1張票
可以正常買票,問題解決;