关于读写锁算法的Java实现及思考

来源:互联网 发布:蒙文软件下载 编辑:程序博客网 时间:2024/05/18 21:48

问题背景:多个线程对一个共享的资源进行读写访问。写线程之间需要互斥,读线程跟写线程需要互斥,读线程之间不用互斥。

早些时候听张sir的课,讲述java5中增强并发的功能。用java.util.concurrent.locks中ReadWriteLock 可以轻松解决读写锁问题。我在思考如果没有ReadWriteLock,单靠synchronized可以怎样做呢? 的确,比较麻烦。

1.结合张sir传授的面向对象的设计思想,首先设计一个业务类Business作为共享资源,封装write跟read方法。

2.因为write必定互斥,所以直接定义synchronized。

3.read之间不要互斥 所以read 不能直接定义synchronized的 但是 write跟read 需要互斥 如何控制 我想到的一个方法是在read里 加入synchronized(this){} 同时定义readThreads计数器作为信号量 我试想下会出现下面几种情况:

read[m]表示某个线程的read方法 。

write[n] 同上

1>read[m]中执行到synchronized(this){readThreads++;}时 write[n]来了 write[n] 会被自身的synchronized阻塞。

2>read[m]在do something(此时无锁)时 write[n] 来了 因为 readThreads!=0 而被迫wait。

3> 每次read[m]结束时 wait中的write[n]会被notify 但如果发现还有其他的read的话 write[n] 只能无奈地再次wait。

4>当readThreads==0并且调用notifyAll 时 read[m] 和 write[n] 会竞争cpu 如果write[n]再次落败,则会出现1>或3> ; 如果成了,则如下:

5> 如果write[n] wait中醒来占锁,read[m]被阻塞synchronized(this){readThreads++;}之上。

6>如果被阻塞的write[n]占锁,read[m]被阻塞synchronized(this){readThreads++;}之上。

从以上看来read 和 write 是互斥的。

4.实现细节如下:<如有错误欢迎指出交流>

  1. package communication;
  2. import java.util.Random;
  3. public class ReadWriteLockTest {
  4. public static void main(String[] args){
  5. final Business business = new Business();
  6. //启动4线程 2读 2写
  7. for(int i=1;i<=2;i++){
  8. new Thread(new Runnable(){
  9. public void run() {
  10. for(int j=1;j<1000;j++){
  11. business.read();
  12. try {
  13. Thread.sleep(900);
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. }
  19. }).start();
  20. new Thread(new Runnable(){
  21. public void run() {
  22. Random r = new Random();
  23. for(int j=1;j<1000;j++){
  24. int i = r.nextInt(100);
  25. business.write(i);
  26. try {
  27. Thread.sleep(1000);
  28. } catch (InterruptedException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }
  33. }).start();
  34. }
  35. }
  36. }
  37. //封装的业务类
  38. class Business{
  39. private int data=0; //共享资源属性
  40. private int readThreads = 0; //读线程数
  41. //private boolean isWriting = false;
  42. //是否执行写 后来发现不需要 当write抢占锁时 所有的read 都被挡在synchronized (this){}之上 无机会执行wait
  43. public void read(){
  44. synchronized (this) {
  45. /*while(isWriting){
  46. try {
  47. this.wait();
  48. } catch (InterruptedException e) {
  49. // TODO Auto-generated catch block
  50. e.printStackTrace();
  51. }
  52. }*/
  53. //readThreads不被锁的话 会出现read和write不互斥的小概率事件 导致线程不安全
  54. readThreads++;
  55. }
  56. System.out.println(Thread.currentThread().getName()+" read begin");
  57. System.out.println(Thread.currentThread().getName()+" read:"+data);
  58. System.out.println(Thread.currentThread().getName()+" read finish");
  59. synchronized (this) {
  60. readThreads--;
  61. this.notifyAll();
  62. }
  63. }
  64. public synchronized void write(int i){
  65. while(readThreads != 0){//当read 正处于do something状态时 来个write 那就只有等等先了
  66. try {
  67. this.wait();
  68. } catch (InterruptedException e) {
  69. e.printStackTrace();
  70. }
  71. }
  72. //isWriting = true;
  73. System.out.println(Thread.currentThread().getName()+" write start");
  74. data = i;
  75. System.out.println(Thread.currentThread().getName()+" write:"+i);
  76. System.out.println(Thread.currentThread().getName()+" write over");
  77. //isWriting = false;
  78. this.notifyAll();
  79. }
  80. }

思考中:

5.当读频繁时 readThreads会长时间!= 0 写线程会饿死 这个可以如何解决?

原文链接:http://www.cnblogs.com/hottea4Goodspeed/archive/2012/03/06/2381257.html

原创粉丝点击