Java线程同步实例分析

时间:2022-04-24 04:28:05

本文实例讲述了Java线程同步的用法。分享给大家供大家参考。具体分析如下:

多线程的使用为我们的程序提供了众多的方便,同时它也给我们带来了以往没有考虑过的麻烦。当我们使用多线程处理共享资源时意外将会发生:比如我们一起外出就餐,每个人都是一个线程,餐桌上的食物则是共享资源,当我看到红烧鸡腿上桌后立即拿起筷子直奔目标,眼看着就得手的时候,突然~~~鸡腿消失了,一个距离盘子更近的线程正在得意地啃着。

为了避免上述问题的发生,Java为我们提供了“synchronized(同步化)修饰符”来避免资源冲突,你可以将资源类中某个函数或变量声明为synchronized(同步化),每个继承自Object的类都含有一个机锁(Lock),它是余生俱来的,不需要编写任何代码来启用它。当我们调用任何synchronized(同步化)函数时,该对象将被锁定,对象中所有 synchronized(同步化)函数便无法被调用,直到第一个函数执行完毕并解除机锁。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
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;
/**
 * 线程同步
 * 我们模拟一个银行存储过程来证明线程同步的必要性以及在Java中进行线程同步的方法
 * 重点:synchronized 修饰符
 */
public class TestMain5 extends JFrame {
 private MyAccounts myAccounts = null; // 我的帐号
 private JTextField text = null; // 银行存款数额显示
 private JTextArea textArea = null; // 交易过程显示
 private JButton button = null; // 开始模拟交易的按钮
 /**
  * 构造一个银行存取款界面
  */
 public TestMain5(){
  super("线程同步测试");
  myAccounts = new MyAccounts();
  text = new JTextField(Integer.toString(myAccounts.inquire()), 10); // 我们在银行中的初始存款为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);
 }
 /**
  * 银行交易大厅类
  * 一般银行都会有N个交易大厅,这些大厅可以同时处理多笔业务,这正好符合多线程的特点
  */
 class Bank extends Thread{
  /**
   * 静态字段:用于表示储存
   */
  public static final int DEAL_SAVING = 0;
  /**
   * 静态字段:用于表示提取
   */
  public static final int DEAL_FETCH = 1;
  private int buy = Bank.DEAL_FETCH; // 默认使取款
  private int count = 0;
  private MyAccounts myAccounts = null; // 我的帐号
  /**
   * 构造这个银行交易大厅
   * @param name 这个交易大厅的名称
   * @param myAccounts 我的银行帐号
   * @param buy 行为,参考字段:DEAL_SAVING或DEAL_FETCH
   * @param count 钱的数量
   */
  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){ // 如果是存款业务
    $count = myAccounts.saving(count);
   }else if(buy == Bank.DEAL_FETCH){ // 如果是取款业务
    $count = myAccounts.fetch(count);
   }
   text.setText(Integer.toString($count));
   textArea.append("\n" + this.getName() + " " + (buy == Bank.DEAL_SAVING ? "存款": "取款") + " 金额:" + count + " 结余:" + $count);
  }
 }
 /**
  * 我的帐号
  * 进行同步测试
  */
 class MyAccounts{
  private Integer count = 1100;
  public MyAccounts(){
  }
  /**
   * 查询我的帐号
   */
  public int inquire(){
   synchronized (count){
    return count;
   }
  }
  /**
   * 存款业务
   * @param c 存款的数量
   * @return 业务办理完成后的数量
   */
  public int saving(int c){
   synchronized (count){
    //return count += c; // 为了能更好的观察,我们将这个简洁的语句注释掉
    int $count = inquire(); // 先查询帐户中的存款
    $count += c;
    try {
     Thread.sleep(1000); // 为了更好的观察,使业务在此停顿1秒钟
    } catch (InterruptedException ex) {
     ex.printStackTrace();
    }
    count = $count; // 最后将总数储存起来
    return inquire(); // 返回最新的存款数
   }
  }
  /**
   * 取款业务
   * @param c 取款的数量
   * @return 业务办理完成后的数量
   */
  public int fetch(int c){
   synchronized (count){
    //return count -= c; // 为了能更好的观察,我们将这个简洁的语句注释掉
    int $count = inquire(); // 先查询帐户中的存款
    $count -= c;
    try {
     Thread.sleep(1000); // 为了更好的观察,使业务在此停顿1秒钟
    } catch (InterruptedException ex) {
     ex.printStackTrace();
    }
    count = $count; // 最后将总数储存起来
    return inquire(); // 返回最新的存款数
   }
  }
 }
 public static void main(String [] args){
  new TestMain5();
 }
}

希望本文所述对大家的java程序设计有所帮助。