您的位置:首页 > 编程语言 > Java开发

synchronized关键字、ReentrantLock与原子类比较

2016-11-28 20:59 579 查看
我们先比较ReentrantLock与synchronized的用法
1、ReentrantLock拥有synchronized相同的并发性和内存语义,此外还多了锁投票,定时锁等候和中断等候。线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定。

使用synchronized时,如果A不释放,B将一直等待下去,无法中断。

使用ReentrantLock时,如果A不释放,B可以在等待足够长时间后,停止等待,继续执行其他事务。
ReentrantLock获取锁定的三种方式:

lock(),如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直至获取锁。

tryLock(),如果获取了锁立即返回true,如果别的线程下持有,立即返回false;

tryLock(long timeout, TimeUnit unit),如果获取了锁定立即返回true,如果别的线程正持有锁,将等待参数给定的时间,在等待的过程中,如果获取了锁定,返回true,如果等待超时,返回false,所以lock()方法相当trylock传递个无限大的时间参数;

lockInteruptibly,如果获取了锁定立即返回,反之,当前线程处理休眠,直至获取锁,或者当前线程线程被其他线程中断。
2、synchronized是在JVM层面实现,不但可以通过一些监控工具监控锁定,而且在代码执行出现异常,JVM自动释放锁定;

Lock是通过代码实现,为了保证锁定一定会被释放,一般会将unLock()放到flyinal{}中。
3、在资源竞争不激烈的情况下,synchronized的性能要优于ReentrantLock,但在资源竞争很激烈的情况下,synchronized的性能会下降几十倍(jvm需要分配额外的cpu和内存来管理同步),但是ReentrantLock的性能能维持常态。

ReentrantLock例子如下:
package test.lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest1 extends Thread {

private int threadNo;
private static Lock lock = new ReentrantLock();

public LockTest1(int threadNo) {
this.threadNo = threadNo;
}

public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
new LockTest1(i).start();
}
}

@Override
public void run() {
lock.lock();
try {
for (int i = 0; i < 100; i++) {
System.out.println("No." + (threadNo + 1) + ": " + (i + 1));
}
} finally {
lock.unlock();
}
}
}


下面讨论原子类:
synchronized关键字、Lock可以控制程序片段的同步,原子类只能保证单个变量的同步。线程竞争不激烈时,原子类性能比synchronized略低,当竞争激烈时,也能维持常态。

下面是一个多线程共同计数的代码代码。
package test.lock;

public class LockTest2 extends Thread {

private static int race = 0;
private int threadNo;

public LockTest2(int threadNo) {
this.threadNo = threadNo;
}

public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
new LockTest2(i).start();
}

while (Thread.activeCount() > 1) {
Thread.yield();
}
System.out.println(race);
}

@Override
public void run() {
for (int i = 0; i < 1000; i++) {
race++;
}
}
}

上面程序执行后,并没有得到期望的原子类。我们用ActomicInteger实现代码如下:
package test.lock;

import java.util.concurrent.atomic.AtomicInteger;

public class LockTest2 extends Thread {

private static AtomicInteger race = new AtomicInteger();
private int threadNo;

public LockTest2(int threadNo) {
this.threadNo = threadNo;
}

public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
new LockTest2(i).start();
}

while (Thread.activeCount() > 1) {
Thread.yield();
}
System.out.println(race);
}

@Override
public void run() {
for (int i = 0; i < 1000; i++) {
race.addAndGet(1);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐