zoukankan      html  css  js  c++  java
  • 线程同步(一)

    Java的线程同步机制比较少,大致分两种,

    一、锁对象

    示例代码:

    myLock.lock();//a reentrantLock object
    try
    {
        //critical section
    }
    final
    {
        //make sure the lock is unlocked even if an exception is thrown
        myLock.unlock();
    }

    这一结构确保任何时刻只有一个线程进入临界区。一旦一个线程封锁了锁对象,其它任何线程都无法通过lock语句。当其它线程调用lock时,它们被阻塞,直到第一个线程释放锁对象。注意:

    1)此锁对象是对象级的,锁的是对象实例,

    2)此锁对象是可重入的,同一线程中可以lock一次,两次,甚至更多,在同一线程中,如果lock了两次,必须unlock两次,其它线程才能再次访问。

    示例代码:银行转账的示例。代码生成2个账户,每个账户1000元,要求2个账户同时随机转账而不出错。

    银行用Bank类表示,里面实现了转账功能和查询总账的功能,账户用accounts数组表示。

    程序主要由两个工作线程完成,每个工作线程执行这样的动作:向另一个账户转账,然后打印出两个账户的总额。(假设转账是免费的)

    示例代码(此代码必然造成总额出错):

    /**
     * 客户测试代码,测试两个线程同时转账最终出错。
     * @author luhx
     *
     */
    public class BankTransferTest 
    {
        public static void main( String[] args )
        {
            System.out.println( "BankTransferTest begin!" );
            
            Bank b = new Bank();
          
            //第一个转账线程
            TransferRunnable r0 = new TransferRunnable(b, 0, 1);
            Thread t0 = new Thread(r0);
            t0.start();
            
            //第二个转账线程
            TransferRunnable r1 = new TransferRunnable(b, 1, 0);
            Thread t1 = new Thread(r1);
            t1.start();
            
            System.out.println( "BankTransferTest end!");
        }
    }

     

     

    /**

     * 银行类,实现转账功能和查询总账的功能
     * @author luhx
     *
     */
    public class Bank {
        public int []accounts = {1000, 1000};
        
        /**
         * 转账
         * @param from
         * @param to
         * @param money
         */
        void transfermoney(int from, int to, int money)
        {
            if(accounts[from] < money)//
            return ;
            
            accounts[from] -= money;
            accounts[to] += money;
            
            System.out.println("from:" + from + "to:" + to + "money:" + money +"");
            System.out.println("totalMoney: " + getTotalMoney() + "");
     
        }
        
        /**
         * 查询总金额
         * @return
         */
        int getTotalMoney()
        {
            int sum = 0;
            for(int a : accounts)
            {
                sum += a;
            }
            return sum;
        }
    }
     
    /**
     * 线程类,将转账动作绑定到工作线程中执行
     * @author luhx
     *
     */
    public class TransferRunnable implements Runnable{
        private Bank bank;
        private int from;
        private int to;
        final private int DELAY = 100;
        
        TransferRunnable(Bank bank, int from, int to)
        {
            this.bank = bank;
            this.from = from;
            this.to = to;
        }
        
        public void run()
        {
            while(true)
            {
                int toAccount = (int)(1000 * Math.random());
     
                try {
                    bank.transfermoney(from, to, toAccount);
                    Thread.sleep(DELAY);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    经过分析,我们得知,由于两个线程同时对账户1和2进行存取,必然存在冲突,因此需要同步,同步的方法很简单,只需在动到两账户的函数内加上锁即可,重新修改Bank类,然后再运行,发现总额总是2000,不再产生错误。

    /**
     * 银行类,实现转账功能和查询总账的功能
     * @author luhx
     *
     */
    public class Bank {
        public int []accounts = {1000, 1000};
        
        //银行锁
        private Lock bankLock;
        private Condition condition;
        
        
        Bank()
        {
            bankLock = new ReentrantLock();
            condition = bankLock.newCondition();
        }
        /**
         * 转账
         * @param from
         * @param to
         * @param money
         */
        void transfermoney(int from, int to, int money) throws InterruptedException
        {
            bankLock.lock();
            try{
                if(accounts[from] < money)//如果钱不够,则等待
                     condition.await();
                
                accounts[from] -= money;
                accounts[to] += money;
                System.out.println("from:" + from + "to:" + to + "money:" + money +"");
                System.out.println("totalMoney: " + getTotalMoney() + "");
                
                condition.signalAll();
            }
            finally
            {
                bankLock.unlock();
            }
        }
        
        /**
         * 查询总金额
         * @return
         */
        int getTotalMoney()
        {
            bankLock.lock();
            try{
                int sum = 0;
                for(int a : accounts)
                {
                    sum += a;
                }
                return sum;
            }
            finally
            {
                bankLock.unlock();
            }
     
        }
    }

    使用对象锁比较麻烦,需要比较多的额外代码,可以用synchronized进行简化,使用之重改Bank类后如下所示

    /**
     * 银行类,实现转账功能和查询总账的功能
     * @author luhx
     *
     */
    public class Bank {
        public int []accounts = {1000, 1000};
     
        /**
         * 转账
         * @param from
         * @param to
         * @param money
         */
        public synchronized void transfermoney(int from, int to, int money) throws InterruptedException
        {
            if(accounts[from] < money)//如果钱不够,则等待
                 wait();
            
            accounts[from] -= money;
            accounts[to] += money;
            System.out.println("from:" + from + "to:" + to + "money:" + money +"");
            System.out.println("totalMoney: " + getTotalMoney() + "");
            
            notifyAll();
            
        }
        
        /**
         * 查询总金额
         * @return
         */
        public synchronized int getTotalMoney()
        {
            try{
                int sum = 0;
                for(int a : accounts)
                {
                    sum += a;
                }
                return sum;
            }
            finally
            {
            }
     
        }
    }
  • 相关阅读:
    day01--计算机硬件基础笔记
    22 Jun 18 Django,ORM
    21 Jun 18 Django,ORM
    20 Jun 18 复习, mysql
    20 Jun 18 Django,ORM
    19 Jun 18 复习, 正则表达式
    19 Jun 18 Django
    15 Jun 18 复习, shutil模块
    15 Jun 18 Django
    14 Jun 18 复习, form表单
  • 原文地址:https://www.cnblogs.com/luhouxiang/p/2287633.html
Copyright © 2011-2022 走看看