Java線程同步實(shí)例分析
本文實(shí)例講述了Java線程同步的用法。分享給大家供大家參考。具體分析如下:
多線程的使用為我們的程序提供了眾多的方便,同時(shí)它也給我們帶來了以往沒有考慮過的麻煩。當(dāng)我們使用多線程處理共享資源時(shí)意外將會(huì)發(fā)生:比如我們一起外出就餐,每個(gè)人都是一個(gè)線程,餐桌上的食物則是共享資源,當(dāng)我看到紅燒雞腿上桌后立即拿起筷子直奔目標(biāo),眼看著就得手的時(shí)候,突然~~~雞腿消失了,一個(gè)距離盤子更近的線程正在得意地啃著。
為了避免上述問題的發(fā)生,Java為我們提供了“synchronized(同步化)修飾符”來避免資源沖突,你可以將資源類中某個(gè)函數(shù)或變量聲明為synchronized(同步化),每個(gè)繼承自O(shè)bject的類都含有一個(gè)機(jī)鎖(Lock),它是余生俱來的,不需要編寫任何代碼來啟用它。當(dāng)我們調(diào)用任何synchronized(同步化)函數(shù)時(shí),該對(duì)象將被鎖定,對(duì)象中所有 synchronized(同步化)函數(shù)便無法被調(diào)用,直到第一個(gè)函數(shù)執(zhí)行完畢并解除機(jī)鎖。
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* 線程同步
* 我們模擬一個(gè)銀行存儲(chǔ)過程來證明線程同步的必要性以及在Java中進(jìn)行線程同步的方法
* 重點(diǎn):synchronized 修飾符
*/
public class TestMain5 extends JFrame {
private MyAccounts myAccounts = null; // 我的帳號(hào)
private JTextField text = null; // 銀行存款數(shù)額顯示
private JTextArea textArea = null; // 交易過程顯示
private JButton button = null; // 開始模擬交易的按鈕
/**
* 構(gòu)造一個(gè)銀行存取款界面
*/
public TestMain5(){
super("線程同步測(cè)試");
myAccounts = new MyAccounts();
text = new JTextField(Integer.toString(myAccounts.inquire()), 10); // 我們?cè)阢y行中的初始存款為100
textArea = new JTextArea();
textArea.setText("交易日志:");
JScrollPane sp = new JScrollPane(textArea);
button = new JButton("開始交易");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
new Bank("鐘樓支行", myAccounts, Bank.DEAL_SAVING, 800);
new Bank("高新支行", myAccounts, Bank.DEAL_SAVING, 1300);
new Bank("小寨支行", myAccounts, Bank.DEAL_FETCH, 200);
new Bank("雁塔支行", myAccounts, Bank.DEAL_FETCH, 400);
new Bank("興慶支行", myAccounts, Bank.DEAL_SAVING, 100);
new Bank("土門支行", myAccounts, Bank.DEAL_FETCH, 700);
}
});
JPanel pane = new JPanel();
pane.add(text);
pane.add(button);
this.getContentPane().add(pane, BorderLayout.NORTH);
this.getContentPane().add(sp);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(300, 200);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
/**
* 銀行交易大廳類
* 一般銀行都會(huì)有N個(gè)交易大廳,這些大廳可以同時(shí)處理多筆業(yè)務(wù),這正好符合多線程的特點(diǎn)
*/
class Bank extends Thread{
/**
* 靜態(tài)字段:用于表示儲(chǔ)存
*/
public static final int DEAL_SAVING = 0;
/**
* 靜態(tài)字段:用于表示提取
*/
public static final int DEAL_FETCH = 1;
private int buy = Bank.DEAL_FETCH; // 默認(rèn)使取款
private int count = 0;
private MyAccounts myAccounts = null; // 我的帳號(hào)
/**
* 構(gòu)造這個(gè)銀行交易大廳
* @param name 這個(gè)交易大廳的名稱
* @param myAccounts 我的銀行帳號(hào)
* @param buy 行為,參考字段:DEAL_SAVING或DEAL_FETCH
* @param count 錢的數(shù)量
*/
public Bank(String name, MyAccounts myAccounts, int buy, int count){
super(name);
this.myAccounts = myAccounts;
this.buy = buy;
this.count = count;
this.start();
}
public void run(){
int $count = 0;
if(buy == Bank.DEAL_SAVING){ // 如果是存款業(yè)務(wù)
$count = myAccounts.saving(count);
}else if(buy == Bank.DEAL_FETCH){ // 如果是取款業(yè)務(wù)
$count = myAccounts.fetch(count);
}
text.setText(Integer.toString($count));
textArea.append("\n" + this.getName() + " " + (buy == Bank.DEAL_SAVING ? "存款": "取款") + " 金額:" + count + " 結(jié)余:" + $count);
}
}
/**
* 我的帳號(hào)
* 進(jìn)行同步測(cè)試
*/
class MyAccounts{
private Integer count = 1100;
public MyAccounts(){
}
/**
* 查詢我的帳號(hào)
*/
public int inquire(){
synchronized (count){
return count;
}
}
/**
* 存款業(yè)務(wù)
* @param c 存款的數(shù)量
* @return 業(yè)務(wù)辦理完成后的數(shù)量
*/
public int saving(int c){
synchronized (count){
//return count += c; // 為了能更好的觀察,我們將這個(gè)簡潔的語句注釋掉
int $count = inquire(); // 先查詢帳戶中的存款
$count += c;
try {
Thread.sleep(1000); // 為了更好的觀察,使業(yè)務(wù)在此停頓1秒鐘
} catch (InterruptedException ex) {
ex.printStackTrace();
}
count = $count; // 最后將總數(shù)儲(chǔ)存起來
return inquire(); // 返回最新的存款數(shù)
}
}
/**
* 取款業(yè)務(wù)
* @param c 取款的數(shù)量
* @return 業(yè)務(wù)辦理完成后的數(shù)量
*/
public int fetch(int c){
synchronized (count){
//return count -= c; // 為了能更好的觀察,我們將這個(gè)簡潔的語句注釋掉
int $count = inquire(); // 先查詢帳戶中的存款
$count -= c;
try {
Thread.sleep(1000); // 為了更好的觀察,使業(yè)務(wù)在此停頓1秒鐘
} catch (InterruptedException ex) {
ex.printStackTrace();
}
count = $count; // 最后將總數(shù)儲(chǔ)存起來
return inquire(); // 返回最新的存款數(shù)
}
}
}
public static void main(String [] args){
new TestMain5();
}
}
希望本文所述對(duì)大家的java程序設(shè)計(jì)有所幫助。
相關(guān)文章
Java 連接Access數(shù)據(jù)庫的兩種方式
這篇文章主要介紹了Java 連接Access數(shù)據(jù)庫的兩種方式,本文著重講解使用JDBC連接操作Access數(shù)據(jù)庫,需要的朋友可以參考下2015-06-06
在SpringBoot項(xiàng)目中的使用Swagger的方法示例
這篇文章主要介紹了在SpringBoot項(xiàng)目中的使用Swagger的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
Spring?Boot應(yīng)用程序中如何使用Keycloak詳解
這篇文章主要為大家介紹了Spring?Boot應(yīng)用程序中如何使用Keycloak詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
項(xiàng)目為什么引入log4j而不是logback代碼
這篇文章主要介紹了項(xiàng)目為什么引入log4j而不是logback代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
詳解SpringCloud eureka服務(wù)狀態(tài)監(jiān)聽
這篇文章主要介紹了詳解SpringCloud eureka服務(wù)狀態(tài)監(jiān)聽,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07
Springboot如何切換默認(rèn)的Tomcat容器
這篇文章主要介紹了Springboot如何切換默認(rèn)的Tomcat容器,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
springboot 返回json格式數(shù)據(jù)時(shí)間格式配置方式
這篇文章主要介紹了springboot 返回json格式數(shù)據(jù)時(shí)間格式配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11

