Java公平锁与非公平锁

定义

当程序使用多线程里,难免有多线程争夺资源的情况。而资源只能被一个线程独占使用,至于资源怎么分配,就涉及到非公平锁与公平锁了。

非公平锁:非公平锁的资源的分配是随机的,看谁先抢到就给谁。可能会出现一个线程长期霸占资源,而另一线程长期得不到资源。
公平锁:顾名思义,公平锁的资源是公平分配的,先来先得,后来排队。

实例

开20个线程进行计数,每个线程计算到10000,最后

非公平锁之synchroized实现

使用synchroized锁的都是非公平锁。实现如下


import org.springframework.util.StopWatch;

public class ClassTestApp4lication {

    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) {
                            System.out.println("线程ID:"+Thread.currentThread().getId());//输出当前线程ID,便于确认分配的机制
                            i = i + 1;
                        }
                    }
                }
            };
            t1.start();
        }
    }
}

因为输出的结果太长了,这里抽取部分输出结果,如下:
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:12
线程ID:14
线程ID:14
线程ID:14
线程ID:14
线程ID:14
线程ID:27
线程ID:27
线程ID:27
线程ID:27

非公平锁之ReentrantLock实现

用ReentrantLock实现,关键在于实例化ReentrantLock时传参为false。使用无参数重载也是非公平锁,如:
public static ReentrantLock rlock=new ReentrantLock(false)
或者 public static ReentrantLock rlock=new ReentrantLock()。
代码如下:


import org.springframework.util.StopWatch;
import java.util.concurrent.locks.ReentrantLock;
public class ClassTest3Application {
    public static ReentrantLock rlock=new ReentrantLock(false);//false表示非公平锁,或使用无参数重载。
    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 < 1000; ac2++) {
                        try {
                            rlock.lock();
                            System.out.println("线程ID:"+Thread.currentThread().getId());
                            i = i + 1;
                        } finally {
                            rlock.unlock();
                        }
                    }
                }
            };
            t1.start();
        }
    }
}

同样这里也只贴出部分的输出,如下
线程ID:12
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:17
线程ID:28
线程ID:28

公平锁 ReentrantLock实现

用ReentrantLock实现,关键在于实例化ReentrantLock时传参为true。如:
public static ReentrantLock rlock=new ReentrantLock(true)


import org.springframework.util.StopWatch;
import java.util.concurrent.locks.ReentrantLock;
public class ClassTest3Application {
    public static ReentrantLock rlock=new ReentrantLock(true);//true 表示公平锁
    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 < 1000; ac2++) {
                        try {
                            rlock.lock();
                            System.out.println("线程ID:"+Thread.currentThread().getId());
                            i = i + 1;
                        } finally {
                            rlock.unlock();
                        }
                    }
                }
            };
            t1.start();
        }
    }
}

同样这里也只贴出部分的输出,如下
线程ID:12
线程ID:13
线程ID:14
线程ID:15
线程ID:16
线程ID:17
线程ID:12
线程ID:18
线程ID:19
线程ID:13
线程ID:20
线程ID:14
线程ID:21
线程ID:15
线程ID:22
线程ID:16
线程ID:23
线程ID:17
线程ID:24
线程ID:12
线程ID:25
线程ID:18
线程ID:26
线程ID:19

性能测试

性能测试场景

开启20个线程,每个线程计数1000000次。计划耗时

测试结果

synchronized 非公平锁

测试序号 耗时(单位为秒)
1 0.5398486
2 0.5319575
3 0.5299667
4 0.5496109
5 0.5520412

ReentrantLock 非公平锁

测试序号 耗时(单位为秒)
1 0.4283422
2 0.4390329
3 0.4378793
4 0.4409746
5 0.4377871

ReentrantLock 公平锁

测试序号 耗时(单位为秒)
1 209.9848296

这个比较久,我等了好几分钟,就只做一次测试吧。

结论

性能 描述
synchronized 非公平锁 很好 耗时在0.54秒样子
ReentrantLock 非公平锁 最好 耗时在0.43秒样子
ReentrantLock 公平锁 最差 耗时超过200秒,与非公平锁不是一样等级,公平是有代价的。
发布了2 篇原创文章 · 获赞 0 · 访问量 1223

猜你喜欢

转载自blog.csdn.net/richyliu44/article/details/104254560