黑马程序员-读写锁和缓存类

------- android培训java培训期待与您交流 ----------

 

读写锁:

   分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥,也就是说可以多个线程在读取数据,不能一边在读取数据一边在写入数据,也不能一个线程在写另一个线程也在写,保证了数据的完整性。

创建读写锁:

  ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

设置、释放读写锁:

  rwl.readLock().lock(); 设置读锁

  rwl.readLock().unlock(); 释放读锁

  rwl.writeLock().lock();设置写锁

  rwl.writeLock().unlock(); 释放写锁

注意:释放锁的操作必须放到finally中,即使前面的代码发生异常也要释放资源。

 1     public static void main(String[] args) {
 2         // 创建线程数固定为5的线程池
 3         ExecutorService threadPool = Executors.newFixedThreadPool(5);
 4         //内部类在局部时只能访问被final修饰的局部变量
 5         final ReadWrite rw = new ReadWrite();
 6         for (int i = 0; i < 10; i++) {
 7             //内部类在局部时只能访问被final修饰的局部变量
 8             final int num = i;
 9             //添加任务
10             threadPool.execute(new Runnable() {
11                 
12                 @Override
13                 public void run() {
14                     //交替执行读写操作
15                     if (num % 2 == 0) {
16                         rw.write("ssssss");
17                     }else{
18                         rw.read();
19                     }
20                 }
21             });
22         }
23     }
24 
25     static class ReadWrite {
26         private String value;
27         // 创建读写锁
28         private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
29 
30         //
31         public void read() {
32             //设置读锁
33             rwl.readLock().lock();
34             try {
35                 
36                 System.out.println(Thread.currentThread().getName() + "read data ");
37                 System.out.println(value);
38                 System.out.println("end read data");
39             } finally {
40                 
41                 //释放读锁
42                 //释放锁操作一定要放在finally中,因为前面有可能发生异常,如果没放在finally中就不能释放资源
43                 rwl.readLock().unlock();
44             }
45         }
46 
47         //
48         public void write(String num) {
49             //设置写锁
50             rwl.writeLock().lock();
51             try {
52                 System.out.println(Thread.currentThread().getName() +"write data begin!");
53                 Thread.sleep(10);
54                 value = num;
55                 System.out.println(Thread.currentThread().getName() +"write data ........end!");
56             }catch(Exception e){
57                 
58             } finally {
59                 //释放写锁
60                 rwl.writeLock().unlock();
61             }
62         }
63     }

 

缓存类

 1 package cn.itcst.day5;
 2 
 3 import java.util.HashMap;
 4 import java.util.Map;
 5 import java.util.concurrent.ExecutorService;
 6 import java.util.concurrent.Executors;
 7 import java.util.concurrent.locks.ReadWriteLock;
 8 import java.util.concurrent.locks.ReentrantReadWriteLock;
 9 
10 /**
11  * 缓存类
12  * 
13  * @author Administrator
14  * 
15  */
16 public class CacheDemo {
17 
18     public static void main(String[] args) {
19         // TODO Auto-generated method stub
20         //创建线程池
21         ExecutorService threadPool = Executors.newFixedThreadPool(3);
22         for (int i = 0; i < 3; i++) {
23             threadPool.execute(new Runnable() {
24 
25                 @Override
26                 public void run() {
27 //                    调用方法
28                     System.out.println("main方法中输出:" + get());
29 
30                 }
31             });
32         }
33 
34     }
35     static Map<String, String> map = new HashMap<String, String>();
36     public static String get() {
37         // 创建读写锁
38         ReadWriteLock rwl = new ReentrantReadWriteLock();
39         String name;
40         // 设置读锁
41         rwl.readLock().lock();
42         try {
43             //每次获得都是为null!!!!
44             name = map.get("id");
45             System.out.println("重新进入方法集合的长度为:" + map.size());
46             try {
47                 Thread.sleep(200);
48             } catch (InterruptedException e) {
49                 // TODO Auto-generated catch block
50                 e.printStackTrace();
51             }
52             if (name == null) {
53                 // 如果name为null就释放读锁
54                 rwl.readLock().unlock();
55                 // 设置写锁,进行赋值
56                 rwl.writeLock().lock();
57                 try {
58                     //每个线程都会进来!!!!
59                     System.out.println(Thread.currentThread().getName() + "--jin--"
60                             + name);
61                     // 赋值并存入集合
62                     name = "zhangsan";
63                     map.put("id", name);
64                     System.out.println("在把数据存入集合后根据ID获得name: " + map.get("id"));
65                 } finally {
66                     rwl.readLock().lock();
67                     // 释放写锁
68                     rwl.writeLock().unlock();
69                 }
70             }
71 
72         } finally {
73             // 释放读锁
74             rwl.readLock().unlock();
75         }
76         return name;
77     }
78 
79 }

控制台输出:

重新进入方法集合的长度为:0
重新进入方法集合的长度为:0
重新进入方法集合的长度为:0
pool-1-thread-3--jin--null
在把数据存入集合后根据ID获得name: zhangsan
main方法中输出:zhangsan
pool-1-thread-2--jin--null
在把数据存入集合后根据ID获得name: zhangsan
main方法中输出:zhangsan
pool-1-thread-1--jin--null
在把数据存入集合后根据ID获得name: zhangsan
main方法中输出:zhangsan

在上面代码中有个问题没有解决,单纯的在读锁中读取和切换到写锁中写数据是没有问题的,但是我想在第一次写入之后存入集合避免以后进来都创建锁、写数据一系列动作,每次存到map的数据在再次访问的时候都没有了,本来我以为是线程太快排进去了,就在run方法中叫了sleep(),但是还是不行。

最后我在分配任务前也加了sleep(),居然就正常了,由此推断还是因为运行得太快全部都排进去了,但是不知道为什么在Run方法中调用方法前sleep()没有作用,或许是线程池分配任务机制有所不同

 1 public static void main(String[] args) {
 2         // TODO Auto-generated method stub
 3         //创建线程池
 4         ExecutorService threadPool = Executors.newFixedThreadPool(3);
 5         for (int i = 0; i < 3; i++) {
 6             try {
 7                 Thread.sleep(2000);
 8             } catch (InterruptedException e) {
 9                 // TODO Auto-generated catch block
10                 e.printStackTrace();
11             }
12             threadPool.execute(new Runnable() {
13 
14                 @Override
15                 public void run() {
16 //                    调用方法
17                     System.out.println("main方法中输出:" + get());
18 
19                 }
20             });
21         }
22 
23 
24     }
25     static Map<String, String> map = new HashMap<String, String>();
26     public static String get() {
27         // 创建读写锁
28         ReadWriteLock rwl = new ReentrantReadWriteLock();
29         String name;
30         // 设置读锁
31         
32         rwl.readLock().lock();
33         try {
34             
35             name = map.get("id");
36             System.out.println("重新进入方法集合的长度为:" + map.size());
37             try {
38                 Thread.sleep(200);
39             } catch (InterruptedException e) {
40                 // TODO Auto-generated catch block
41                 e.printStackTrace();
42             }
43             if (name == null) {
44                 // 如果name为null就释放读锁
45                 rwl.readLock().unlock();
46                 // 设置写锁,进行赋值
47                 rwl.writeLock().lock();
48                 try {
49                     System.out.println(Thread.currentThread().getName() + "--jin--"
50                             + name);
51                     // 赋值并存入集合
52                     name = "zhangsan";
53                     map.put("id", name);
54                     System.out.println("在把数据存入集合后根据ID获得name: " + map.get("id"));
55                 } finally {
56                     rwl.readLock().lock();
57                     // 释放写锁
58                     rwl.writeLock().unlock();
59                 }
60             }
61 
62         } finally {
63             // 释放读锁
64             rwl.readLock().unlock();
65         }
66         return name;
67     }

控制台输出:

重新进入方法集合的长度为:0
pool-1-thread-1--jin--null
在把数据存入集合后根据ID获得name: zhangsan
main方法中输出:zhangsan
重新进入方法集合的长度为:1
main方法中输出:zhangsan
重新进入方法集合的长度为:1
main方法中输出:zhangsan

 

posted @ 2013-03-04 22:12  walk on by  阅读(283)  评论(0编辑  收藏  举报