为什么synchronized不能锁住代码块而ReentrantLock可以

J2EE 码拜 9年前 (2016-03-12) 1476次浏览
public class Test{
        public static void main(String[] args) {
                //创建并发访问的账户
                MyCount myCount = new MyCount("95599200901215522", 10000);
                //创建一个锁对象
                Lock lock = new ReentrantLock();
                //创建一个线程池
                ExecutorService pool = Executors.newCachedThreadPool(); 
                //创建一些并发访问用户,一个信用卡,存的存,取的取,好热闹啊
                User1 u1 = new User1("张三", myCount, -4000, lock); 
                User1 u2 = new User1("张三他爹", myCount, 6000, lock); 
                User1 u3 = new User1("张三他弟", myCount, -8000, lock); 
                User1 u4 = new User1("张三", myCount, 800, lock);
                //在线程池中执行各个用户的操作
                pool.execute(u1); 
                pool.execute(u2); 
                pool.execute(u3); 
                pool.execute(u4); 
                //关闭线程池
                pool.shutdown(); 
        } 
} 
/** 
* 信用卡的用户 
*/ 
class User1 implements Runnable { 
        private String name;                //用户名
        private MyCount myCount;        //所要操作的账户
        private int iocash;                //操作的金额,当然有正负之分了
        private Lock myLock;                //执行操作所需的锁对象
        User1(String name, MyCount myCount, int iocash, Lock myLock) {
                this.name = name;
                this.myCount = myCount;
                this.iocash = iocash;
                this.myLock = myLock;
        } 
        public void run() {
            //获取锁
//            myLock.lock();
            synchronized(this){
            
            //执行现金业务
            System.out.println(name + "正在操作" + myCount +"账户,金额为" + iocash +",当前金额为" + myCount.getCash());
            myCount.setCash(myCount.getCash() + iocash); 
            System.out.println(name + "操作" + myCount +"账户成功,金额为" + iocash +",当前金额为" + myCount.getCash());
            }
            
            //释放锁,否则别的线程没有机会执行了
//            myLock.unlock(); 
        } 
} 
/** 
* 信用卡账户,可随意透支 
*/ 
class MyCount { 
        private String oid;        //账号
        private int cash;            //账户余额
        MyCount(String oid, int cash) {
                this.oid = oid;
                this.cash = cash;
        } 
        public String getOid() {
                return oid;
        } 
        public void setOid(String oid) {
                this.oid = oid;
        } 
        public int getCash() {
                return cash;
        } 
        public void setCash(int cash) {
                this.cash = cash;
        } 
        @Override 
        public String toString() {
                return"MyCount{" +
                                "oid="" + oid + "\"" +
                                ", cash=" + cash +
                                "}"; 
        } 
}

使用ReentrantLock每次运行结果都为:
张三正在操作MyCount{oid=”95599200901215522″, cash=10000}账户,金额为-4000,当前金额为10000
张三操作MyCount{oid=”95599200901215522″, cash=6000}账户成功,金额为-4000,当前金额为6000
张三他爹正在操作MyCount{oid=”95599200901215522″, cash=6000}账户,金额为6000,当前金额为6000
张三他爹操作MyCount{oid=”95599200901215522″, cash=12000}账户成功,金额为6000,当前金额为12000
张三他弟正在操作MyCount{oid=”95599200901215522″, cash=12000}账户,金额为-8000,当前金额为12000
张三他弟操作MyCount{oid=”95599200901215522″, cash=4000}账户成功,金额为-8000,当前金额为4000
张三正在操作MyCount{oid=”95599200901215522″, cash=4000}账户,金额为800,当前金额为4000
张三操作MyCount{oid=”95599200901215522″, cash=4800}账户成功,金额为800,当前金额为4800
而使用synchronized运行结果为:
张三正在操作MyCount{oid=”95599200901215522″, cash=10000}账户,金额为-4000,当前金额为10000
张三操作MyCount{oid=”95599200901215522″, cash=6000}账户成功,金额为-4000,当前金额为6000
张三他弟正在操作MyCount{oid=”95599200901215522″, cash=6000}账户,金额为-8000,当前金额为6000
张三他爹正在操作MyCount{oid=”95599200901215522″, cash=10000}账户,金额为6000,当前金额为10000
张三他爹操作MyCount{oid=”95599200901215522″, cash=4000}账户成功,金额为6000,当前金额为4000
张三他弟操作MyCount{oid=”95599200901215522″, cash=-2000}账户成功,金额为-8000,当前金额为-2000
张三正在操作MyCount{oid=”95599200901215522″, cash=6000}账户,金额为800,当前金额为6000
张三操作MyCount{oid=”95599200901215522″, cash=4800}账户成功,金额为800,当前金额为4800
这是不是说明一个方法进入synchronized块中的时候,另一个方法也进入了synchronized块的代码中

解决方案

60

原因是你同步的对象不对啊。实际上并没有锁住。你需要锁myCount 而不是user,锁住user的实例在你的例子了没有用,用为你new不用的user,每个user的锁都是本人,锁不住,而你用ReentrantLock的时候只有一把锁,说以可以得到正确的结果。

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明为什么synchronized不能锁住代码块而ReentrantLock可以
喜欢 (0)
[1034331897@qq.com]
分享 (0)