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

来源:互联网 发布:一句话经典 知乎 编辑:程序博客网 时间:2024/06/07 12:52
出现:JDK1.5
实现类:
ReentrantLock(重入锁、手工锁)
ReentrantReadWriteLock.ReadLock ReentrantReadWriteLock.WriteLock
主要方法:
lock() unlock()
使用:
TestLock.java
和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方法持有的锁,如果没获取到锁可被其它线程打断
(4)reentrianLock可以指定公平锁(synchronized为不公平锁)
synchronized在锁释放时,所有线程都在竞争锁(不确定谁能拿到锁),很可能有的线程一次都拿不到,不公平
reentrianLock可以在锁竞争时,判断哪个线程等待的时间长,就先让哪个线程获取锁
1
Lock lock = new ReentrainLock(true);//传入true为公平锁,默认为非公平锁

读写锁接口:
ReadWriteLock
实现类:
ReentranReadWriteLock
方法:
readLock、writeLock(返回Lock对象)
使用:
例子:用户从银行读取余额(读锁,多用户同时读一个账号)。用户从银行存取钱(写锁,每次只能一个用户从同一个账号存取钱)

用户账户类: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

测试类: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
 }

原创粉丝点击