Java线程同步实例分析

 更新时间:2015年07月20日 11:19:46   作者:鉴客  
这篇文章主要介绍了Java线程同步用法,实例分析了java中线程同步的相关实现技巧与注意事项,具有一定参考借鉴价值,需要的朋友可以参考下

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

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

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

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程序设计有所帮助。

相关文章

  • Java 连接Access数据库的两种方式

    Java 连接Access数据库的两种方式

    这篇文章主要介绍了Java 连接Access数据库的两种方式,本文着重讲解使用JDBC连接操作Access数据库,需要的朋友可以参考下
    2015-06-06
  • 在SpringBoot项目中的使用Swagger的方法示例

    在SpringBoot项目中的使用Swagger的方法示例

    这篇文章主要介绍了在SpringBoot项目中的使用Swagger的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • SpringBoot的依赖管理配置

    SpringBoot的依赖管理配置

    一般来讲SpringBoot项目是不需要指定版本,而SSM项目是需要指定版本,SpringBoot的核心依赖就是spring-boot-starter-parent和spring-boot-starter-web两个依赖,关于这两个依赖的相关介绍具体今天小编给大家介绍下
    2022-07-07
  • Spring Boot应用程序中如何使用Keycloak详解

    Spring Boot应用程序中如何使用Keycloak详解

    这篇文章主要为大家介绍了Spring Boot应用程序中如何使用Keycloak详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • 项目为什么引入log4j而不是logback代码

    项目为什么引入log4j而不是logback代码

    这篇文章主要介绍了项目为什么引入log4j而不是logback代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • Java SQL注入案例教程及html基础入门

    Java SQL注入案例教程及html基础入门

    这篇文章主要介绍了前端开发每天必学之SQL及HTML入门基础知识,介绍了学习web前端开发需要掌握的基础技术,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • MapStruct Plus的使用教程

    MapStruct Plus的使用教程

    MapStruct和MapStructPlus是Java类型映射的工具,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-12-12
  • 详解SpringCloud eureka服务状态监听

    详解SpringCloud eureka服务状态监听

    这篇文章主要介绍了详解SpringCloud eureka服务状态监听,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • Springboot如何切换默认的Tomcat容器

    Springboot如何切换默认的Tomcat容器

    这篇文章主要介绍了Springboot如何切换默认的Tomcat容器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-06-06
  • springboot 返回json格式数据时间格式配置方式

    springboot 返回json格式数据时间格式配置方式

    这篇文章主要介绍了springboot 返回json格式数据时间格式配置方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11

最新评论