`

Java线程之线程同步

 
阅读更多

转自:http://blog.csdn.net/mq612/article/details/1520583

线程同步

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

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

 

1、两个方法在data上是同步的。
Object data = new Object();
public void method1(){
    synchronized(data){
        //...
    }
}
public void method2(){
    synchronized(data){
        //...
    }
}
2、两个方法是同步的,method1不能同时有两个使用者,method1和method2之间也不能同时被调用。
public synchronized void method1(){
    //...
}
public synchronized void method2(){
    //...
}
3、使用this关键字,效果同上。
public void method1(){
    synchronized (this){
        //...
    }
}
public void method2(){
    synchronized (this){
        //...
    }
}
学会了使用方法,下面就来实际应用一下,我们将要模拟一个银行的存储过程,用线程来模拟银行的各个交易大厅,几乎同时派出6个对同一帐号进行的存取业务,假设每笔业务需要1秒钟来处理,我们来测试一下没有进行同步化处理和进行过同步化的处理的过程和结果。

 

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 修饰符
 * @author 五斗米
 * @blog http://blog.csdn.net/mq612
 */
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();
    }
   
}

上面的例子让我们清楚的看到了当采用线程同步技术后,每笔业务都需等待前一笔操作完成后才能开始,现在请把MyAccounts类两个方法中的synchronized (count)语句注释掉,再运行一下程序,输出结果错了吧?

 

转自:http://blog.csdn.net/mq612/article/details/1520583

分享到:
评论

相关推荐

    JAVA 线程实现数据库的主从同步更新

    在Java编程环境中,...总之,使用Java线程实现数据库主从同步更新是一种常见且实用的技术手段,它涉及到多线程编程、数据库操作、事务管理等多个方面。理解和掌握这些知识点对于开发高可用性的分布式系统至关重要。

    线程 JAVA java线程 java线程第3版 java线程第2版第3版合集

    电子书相关:包含4个有关JAVA线程的电子书(几乎涵盖全部有关线程的书籍) OReilly.Java.Threads.3rd.Edition.Sep.2004.eBook-DDU Java Thread Programming (Sams) java线程第二版中英文 java线程第二版中英文 ...

    Java线程之线程同步synchronized和volatile详解

    Java线程之线程同步synchronized和volatile详解 Java线程同步是Java多线程编程中非常重要的一个方面,主要涉及到线程安全、可见性和有序性三个方面。Java提供了多种同步机制来解决线程安全问题,包括synchronized和...

    java 线程同步 信号量控制同步

    Java 线程同步控制机制 线程同步是 Java 编程中的一种机制,用于控制多个线程之间的资源访问顺序,以避免线程之间的冲突和数据不一致。线程同步的目的就是避免线程“同步”执行,即让多个线程之间排队操作共享资源...

    java线程同步java线程同步

    java线程同步java线程同步java线程同步

    java线程线程安全同步线程

    总的来说,理解和掌握Java线程的创建、状态管理、同步机制和线程安全是进行多线程编程的基础,这对于开发高效、稳定的并发程序至关重要。在实际编程中,应充分利用Java提供的工具和机制,避免潜在的并发问题,提升...

    Java多线程同步论文.doc

    Java多线程同步是Java编程中至关重要的一部分,特别是在并发编程领域。Java提供了多种同步机制来确保线程安全,防止数据不一致性和竞态条件。在Java中,synchronized关键字是实现线程同步的关键,它提供了互斥访问,...

    Java多线程和同步

    Java线程(二):线程同步synchronized和volatile 详细讲解Java 同步的原理技术资料

    java线程同步及通信

    Java线程同步与通信是多线程编程中的关键概念,用于解决并发访问共享资源时可能出现的数据不一致性和竞态条件问题。以下将详细介绍这两个主题,以及如何通过代码示例进行演示。 1. **线程同步**: 线程同步是确保...

    java线程同步详解

    在Java中,我们可以使用`synchronized`关键字来实现线程同步。 线程同步在Java中主要有两种实现方式: 1. **同步方法**:通过在方法声明前加上`synchronized`关键字,可以使得整个方法成为同步方法。这意味着每次...

    java线程.pdf

    ### Java线程同步 为了保证数据的一致性,在多线程环境中需要对共享资源进行同步访问。Java提供了多种机制来实现线程间的同步,包括`synchronized`关键字、显式锁(`ReentrantLock`)、`volatile`关键字等。 #### ...

    Java多线程同步.pdf

    "Java多线程同步.pdf" Java多线程同步是指在Java语言中,如何使用synchronized关键字和其他同步机制来确保多线程程序的正确执行。在Java语言中,synchronized关键字用于对方法或者代码块进行同步,但是仅仅使用...

    java多线程代码案例(创建线程,主线程,线程优先级,线程组,线程同步,线程间的通信)

    本文将深入探讨Java多线程中的关键知识点,包括创建线程、主线程、线程优先级、线程组、线程同步以及线程间的通信。 1. **创建线程** 在Java中,可以通过两种方式创建线程:继承`Thread`类或实现`Runnable`接口。...

    java多线程同步例子

    java多线程同步互斥访问实例,对于初学者或是温故而知新的同道中人都是一个很好的学习资料

    Java 线程同步调用

    在Java中,实现线程同步最常用的方法之一是通过同步方法。在上述代码示例中,`MyThread`类中的`Sell()`方法被声明为`synchronized`。这意味着该方法在执行时会自动锁定当前对象实例,即`this`关键字。当一个线程正在...

    Java线程详解大全

    多线程同步是防止多个线程同时访问共享资源导致数据不一致的重要手段。Java提供了多种同步机制,如`synchronized`关键字、`wait()`、`notify()`和`notifyAll()`方法,以及`Lock`接口(如`ReentrantLock`)等。通过...

    操作系统实验 多线程同步与互斥 java编写 有界面

    操作系统实验是计算机科学教育中的重要组成部分,它...总之,理解和掌握多线程同步与互斥的概念是成为一名合格的Java开发者的关键技能之一。通过实际的编程实验,可以加深对这些概念的理解,并锻炼解决并发问题的能力。

    java线程深入解析

    本文将深入解析Java线程的相关知识点,包括线程的定义、创建、状态管理、线程同步和安全问题。 1. **线程定义** 在Java中,线程是进程中的单一顺序控制流,是程序执行的基本单元。线程在进程的上下文中运行,共享...

    Java多线程同步具体实例.doc

    Java多线程同步是编程中一个非常重要的概念,特别是在并发编程中,用于解决多个线程访问共享资源时可能引发的数据不一致问题。本实例通过一个简单的火车票售票系统来演示同步机制的应用。 在这个实例中,我们创建了...

    java多线程Demo

    Java线程有10个优先级(MIN_PRIORITY, NORM_PRIORITY, MAX_PRIORITY),默认优先级是NORM_PRIORITY。但是,线程优先级并不保证绝对的执行顺序,操作系统调度策略可能影响实际执行顺序。 7. join()方法: 一个线程...

Global site tag (gtag.js) - Google Analytics