您的位置:首页 > 其它

Lock接口与读写锁(lock 和 synchronized 的比较)

2017-08-10 15:31 519 查看
出现:JDK1.5实现类:ReentrantLock(重入锁、手工锁)ReentrantReadWriteLock.ReadLock ReentrantReadWriteLock.WriteLock主要方法:lock() unlock()使用:TestLock.java
1
public class TestLock implement Runnable{
2
3
ReentrantLock lock = new ReentrantLock();
4
5
@Override
6
public void run(){
7
8
try{
9
//加锁
10
lock.lock();
11
//执行同步代码
12
}
13
finally{
14
//释放锁
15
lock.unlock();
16
}
17
18
}
和synchronized互斥锁的比较:(1)synchronized关键字修饰的代码是完全互斥的,而Lock更加灵活,可以实现多线程同时读共享数据(读锁和读锁不互斥),但读锁和写锁互斥。写锁和写锁互斥(读写锁)。(2)ReentrainLock有tryLock方法:
1
public class ReentrainLockTest{
2
//获取锁
3
Lock lock = new ReentrainLock();
4
//线程1的方法:获取锁
5
void m1(){
6
lock.lock();//锁定
7
try{
8
for(int i=0;i<10;i++){//锁定10秒
9
TimeUtil.SECONDS.sleep(1);//sleep 1秒
10
}
11
}catch(InterruptException e){
12
e.printStackTrace();
13
}finally{
14
lock.unlock();//10秒后释放锁
15
}
16
}
17
//线程2的方法
18
void m2(){
19
boolean locked = lock.tryLcok();//尝试锁定,如果返回为false,则获取锁失败,但程序继续执行。
20
Systerm.out.println("是否获得锁:" + locked);
21
if(locked) lock.unlock();//如果获得锁,则解锁
22
}
23
24
public static void main(String[] args){
25
//开启两个线程,线程1调用m1方法,线程2调用m2方法
26
} 
27
}
(3)lockInterruptibly方法持有的锁,如果没获取到锁可被其它线程打断
1
public class{
2
public static void main(Stirng[] args){
3
Lock lock = new ReentrainLock();
4
//1.创建t1线程,一直持有锁
5
Thread t1 = new Thread(()-> {
6
lock.lock();
7
try{
8
while(true){//一直持有锁
9
TimeUtils.SECOND.sleep(1);
10
}
11
}catch(InterruptException e){
12
e.printStackTrace();
13
}fainally{
14
lock.unlock();//释放锁
15
}
16
});
17
t1.start();
18
19
//2.启动t2线程,尝试获取锁,但是一直获取失败(t1线程一直持有锁)
20
Tread t2 = new Thread(()->{
21
try{
22
boolean isLocked = lock.tryLock();
23
lock.lockInterruptibly();//表示可以对其它线程的interrupt方法做出响应
24
System.out.println("t2线程启动!");
25
}catch(InterruptException e){
26
e.printStackTrace();
27
}finally{
28
if(isLocked) lock.unlock();
29
}
30
31
});
32
t2.start();
33
34
//3.主线程1秒后打断t2线程的等待锁状态,t2线程结束,抛出异常
35
try{
36
timeUtils.SECONDS.sleep(1)
37
}catch(InterruptException e){
38
e.printStackTrace();
39
}
40
t2.interrupt();
41
}
42
}
(4)reentrianLock可以指定公平锁(synchronized为不公平锁)synchronized在锁释放时,所有线程都在竞争锁(不确定谁能拿到锁),很可能有的线程一次都拿不到,不公平reentrianLock可以在锁竞争时,判断哪个线程等待的时间长,就先让哪个线程获取锁
1
Lock lock = new ReentrainLock(true);//传入true为公平锁,默认为非公平锁
读写锁接口:ReadWriteLock实现类:ReentranReadWriteLock方法:readLock、writeLock(返回Lock对象)使用:
1
ReadWriteLock rwl = new ReenTranReadWriteLock();
2
rwl.readLock().lock();//获取读锁
3
rwl.readLock().unLock();//释放读锁
4
5
rwl.writeLock().lock();//获取写锁
6
rwl.writeLock().unLock();//释放写锁
例子:用户从银行读取余额(读锁,多用户同时读一个账号)。用户从银行存取钱(写锁,每次只能一个用户从同一个账号存取钱)用户账户类:MyAccount.java
1
public class MyCount {
2
 private String oid; //账号
3
 private int cash; //账户余额
4
5
 MyCount(String oid, int cash) {
6
 this.oid = oid;
7
 this.cash = cash;
8
}
9
10
 public String getOid() {
11
 return oid;
12
}
13
14
 public void setOid(String oid) {
15
 this.oid = oid;
16
}
17
18
 public int getCash() {
19
 return cash;
20
}
21
22
 public void setCash(int cash) {
23
 this.cash = cash;
24
}
25
26
 @Override
27
 public String toString() {
28
 return "MyCount{" +
29
 "oid='" + oid + '\'' +
30
 ", cash=" + cash +
31
 '}';
32
}
33
}
线程类(多用户同时访问一个账号):UserThread.java
1
public class UserThread implements Runnable {
2
 private String name; //用户名
3
 private MyCount myCount; //所要操作的账户
4
 private int iocash; //操作的金额,当然有正负之分了
5
 private ReadWriteLock myLock; //执行操作所需的锁对象
6
 private boolean ischeck; //是否查询
7
8
 public UserThread(String name, MyCount myCount, int iocash, ReadWriteLock myLock, boolean ischeck) {
9
 this.name = name;
10
 this.myCount = myCount;
11
 this.iocash = iocash;
12
 this.myLock = myLock;
13
 this.ischeck = ischeck;//是否查看余额
14
}
15
16
 public void run() {
17
 if (ischeck) {//查看余额
18
 //获取读锁
19
 myLock.readLock().lock();
20
 System.out.println("读:" + name + "正在查询" + myCount + "账户,当前金额为" + myCount.getCash());
21
 //释放读锁
22
 myLock.readLock().unlock();
23
} else {//存取钱
24
 //获取写锁
25
 myLock.writeLock().lock();
26
 //执行现金业务
27
 System.out.println("写:" + name + "正在操作" + myCount + "账户,金额为" + iocash +",当前金额为" + myCount.getCash());
28
 myCount.setCash(myCount.getCash() + iocash);
29
 System.out.println("写:" + name + "操作" + myCount + "账户成功,金额为" + iocash +",当前金额为" + myCount.getCash());
30
 //释放写锁
31
 myLock.writeLock().unlock();
32
}
33
}
34
}
测试类:Test.java
1
public class Test {
2
 public static void main(String[] args) {
3
 //创建并发访问的账户
4
 MyCount myCount = new MyCount("95599200901215522", 10000);
5
 //创建一个锁对象
6
 ReadWriteLock lock = new ReentrantReadWriteLock(false);
7
 //创建一个线程池
8
 ExecutorService pool = Executors.newFixedThreadPool(2);
9
 //创建一些并发访问用户,一个信用卡,存的存,取的取,好热闹啊
10
 User u1 = new User("Mike", myCount, -4000, lock, false);
11
 User u2 = new User("Mike's Dad", myCount, 6000, lock, false);
12
 User u3 = new User("Mike's Brother", myCount, -8000, lock, false);
13
 User u4 = new User("Mike's Mom", myCount, 800, lock, false);
14
 User u5 = new User("Mike's son", myCount, 0, lock, true);
15
 //在线程池中执行各个用户的操作
16
 pool.execute(u1);
17
 pool.execute(u2);
18
 pool.execute(u3);
19
 pool.execute(u4);
20
 pool.execute(u5);
21
 //关闭线程池
22
 pool.shutdown();
23
}
24
}
锁升级和降级原则:读锁不可升级成写锁(读锁释放前不可以加写锁)写锁可以降级成读锁(写锁释放前可以加读锁)官方文档读写锁例子:
1
class CachedData {
2
 Object data;
3
 volatile boolean cacheValid;
4
 final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
5
6
 void processCachedData() {
7
 rwl.readLock().lock();
8
 if (!cacheValid) {//第一重检测,没有缓存数据,释放读锁,加写锁写数据
9
// 在写锁前必须释放读锁
10
rwl.readLock().unlock();
11
rwl.writeLock().lock();
12
try {
13
//第二重检测,写数据前再次确保缓存没有数据,防止在第10行释放了读锁后,被其它线程的写锁拿到,往缓存里写了数据
14
if (!cacheValid) {
15
data = ...//数据库写入修改操作
16
cacheValid = true;
17
}
18
// 锁降级,在写锁里面先上读锁,把写锁降级成读锁
19
rwl.readLock().lock();
20
} finally {
21
rwl.writeLock().unlock(); // 在读锁状态下释放写锁
22
}
23
}
24
25
 try {
26
 use(data);
27
} finally {
28
 rwl.readLock().unlock();
29
}
30
}
31
}

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: