Java悲观锁与乐观锁

锁的目的

多线程编程如有共用资源的使用时,需要保证数据安全,资源需要同步处理。处理资源的手段可以有:互斥同步与非阻塞同步。实现分别对应:悲观锁与乐观锁。

实例

开20个线程进行计数,每个线程计算到10000。分别使用悲观锁与乐观锁来实现。

悲观锁实现

悲观锁是主要使用synchronized实现,通过锁住对应的对象,独占资源的方式。
demo实现代码如下:

import org.springframework.util.StopWatch;

public class ClassTestApplication {
    
    public static Integer i = new Integer(0);
    public static Object oj = new Object();//用于锁对象
    
    public static void main(String[] args) {
        StopWatch watch = new StopWatch();
        watch.start();
        for (int ac = 0; ac < 20; ac++) {
            Thread t1 = new Thread() {
                @Override
                public void run() {
                    for (int ac2 = 0; ac2 < 10000; ac2++) {
                        synchronized (oj) {//锁只能锁对象,不能锁值类型,所以需要另外新建oj对象
                            i = i + 1;
                            Thread.yield();//降低当前线程的优先级
                        }
                    }
                    System.out.println("i=" + i);
                    //输出时耗
                    if (i == 200000) {
                        watch.stop();
                        System.out.println("耗时:" + watch.getTotalTimeSeconds());
                    }
                }
            };
            t1.start();
        }
    }
}

输出结果如下:
i=20480
i=60223
i=71641
i=102771
i=103641
i=117543
i=127194
i=131049
i=140436
i=146951
i=153894
i=160899
i=162207
i=164290
i=170482
i=181676
i=189241
i=194425
i=198873
i=200000
耗时:0.1261655

乐观锁实现

乐观锁主要通过CAS(Compare and swap)去现实。
demo实现代码如下:

import org.springframework.util.StopWatch;
import java.util.concurrent.atomic.AtomicInteger;

public class ClassTest2Application {
    public static AtomicInteger j = new AtomicInteger();
    public volatile static int i;

    public static void main(String[] args) {
        StopWatch watch =new StopWatch();
        watch.start();
        for (int ac = 0; ac < 20; ac++) {
            Thread t1 = new Thread() {
                @Override
                public void run() {
                    for (int ac2 = 0; ac2 < 10000; ac2++) {
                        for (; ; ) { //自旋
                            Integer current = i;
                            Integer next = i + 1;
                            if (j.compareAndSet(current, next)) {  //对比并赋值,注意需要新建一变量current,不能直接使用i
                                i = next;
                                Thread.yield();//降低当前线程的优先级
                                break;
                            }
                        }
                    }
                    System.out.println("i=" + i);
                    if(i==200000)
                    {
                        watch.stop();
                        System.out.println("耗时:"+watch.getTotalTimeSeconds());
                    }
                }
            };
            t1.start();
        }
    }
}

输出结果如下
i=143289
i=146323
i=147099
i=150204
i=150598
i=155177
i=177143
i=184003
i=184685
i=187439
i=188419
i=189595
i=190235
i=192196
i=193054
i=194514
i=194798
i=198438
i=199530
i=200000
耗时:0.0482009

总结

这里只针对domo的场景做一下简单对比。

性能 可读性 复杂度
乐观锁 悲观锁 悲观锁
发布了1 篇原创文章 · 获赞 0 · 访问量 57

猜你喜欢

转载自blog.csdn.net/richyliu44/article/details/104236492
今日推荐