java多线程-对于内置对象锁的理解

在慕课网上看过多线程的课程。

当某一个线程访问到某个类的含有synchronized标志的方法、synchronized的代码块的时候,获得了当前对象的锁,这个时候,其他线程不能访问该对象的这个synchronized方法。比如(慕课网课程上的)能量系统,初始化了一个能量系统,然后有一百个线程去不断获取锁、释放锁实现了能量的转移,一个线程在访问这个能量转移方法的时候,获取了这个EnergySystem的实例对象的锁,其他的线程的就不能操作了。

还有一个减少资源损耗的操作是:当能量不够的时候,为了避免重复申请锁,lockObj.wai()方法调用了,然后进入了waitset等其他线程的lockObj.notifyAll()的调用。

其实也可以在EnergySystem里面进行this的锁,内置对象锁,锁住的是能量系统的实例energySystem,这样很多个转换任务EnergyTransferTask的线程去进行对象内部数组之间能量转换的时候,需要获取的是energySystem的对象锁,然后进行操作,这样操作完成之后才释放锁。

在EnergySystem中锁对象可以这样构建

 //构建锁对象
    private final Object lockObj = new Object();

然后同步的代码块 在EnergySystem中:

synchronized (lockObj){
            //避免持续申请锁
            while (energyBoxes[from] < amount) {
                try {
                    lockObj.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //wait方法调用之后  当前线程进入锁对象上的等待集合中waitset

            System.out.println(Thread.currentThread().getName());
            energyBoxes[from] -= amount;
            System.out.printf("从%d转移%10.2f单位能量到%d",from,amount,to);
            energyBoxes[to] += amount;
            System.out.printf("能量总和: %10.2f %n",getTotalEnergies());

            lockObj.notifyAll();
            //告诉所有等待的线程 不用等待了
        }

注意点

1、此时每个线程都是通过lockObj访问同步代码块,总共只有1把对象锁,单个线程获取了之后其他线程都不能获取这个锁了。所以要等待运行,如果能量不够,还要去锁对象上的waitset等待

2、如果一个线程访问了这个synchronized方法,那么其他所有的synchronized方法也不能被其他线程访问了。


-------------------------------------------------分隔线

在某次讨论中说到了用户购买物品,背景是可以两个地方同时登陆,为了抢一件货物,同时点击购买产生了两次重复购买,都成立,导致了最后账户为负数。

一种解决方案是在sql中加入判断账户余额大于零的语句

一种解决方案是在service层购买货物的地方,通过session集合获取当前用户,然后

synchronized(user){

    //执行购买

}
这样用户的两个session对应的两个购买操作应该也是一个user,他们的操作也是先后进行的。


猜你喜欢

转载自blog.csdn.net/searlas/article/details/79697265
今日推荐