黑马程序员-读写锁和缓存类
作者:互联网
------- 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
转载于:https://www.cnblogs.com/wan-to-fly/archive/2013/03/04/2943497.html
标签:缓存,name,读写,rwl,System,程序员,读锁,println,out 来源: https://blog.csdn.net/weixin_34121282/article/details/93653121