java实现读者-写者问题

来源:互联网 发布:linux ls查看文件大小 编辑:程序博客网 时间:2024/05/01 04:24

问题背景:一个数据文件或记录,可以被多个进程或者线程共享,其中不同的读进程可以并发的访问该临界资源,读和写进程或者线程,不能并发的对该临界资源进行操作,否则造成脏读和脏写,写和写进程之间也是互斥的。而我们今天的读者和写者模式 也称为读写锁,不过这里以信号量的方式进行互斥操作,就可以解决这个问题。
下面来看代码

import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;public class RWTest {    //创建一个用于记录正在读的读进程数    static  int readCount=0;    //创建一个读写线程共享的临界资源    static  int sse=0;    public static void main(String[] args) {      //创建一个线程池        ExecutorService es=Executors.newFixedThreadPool(10);       //创建一个读写互斥的信号量        final Semaphore wmutex=new Semaphore(1,true);        //创建一个用于读进程间的修改临界资源readCount的互斥信号量        final Semaphore rmutex=new Semaphore(1,true);        //创建4个读进程        for(int i=0;i<4;i++){        es.execute(new Runnable(){            @Override            public void run() {              while(!Thread.interrupted()){                  try {                    //获取可以修改readCount的互斥信号量                    rmutex.acquire();                //当readCount==0时说明,不存在读线程获得读写的互斥信号量,该信号量只对写线程操作互斥,对读线程不互斥                    if(readCount==0){                      //获取可以进行IO操作的的互斥信号                        wmutex.acquire();                    }                    readCount++;                    //释放信号量                    rmutex.release();                    //进行IO读操作                    //这里我为了简单明了直接打印                    System.out.println(Thread.currentThread().getId()+"正在进行读操作。。。。。。。。");                    Thread.sleep(100);                    System.out.println("读取的数据为"+sse);                     //获取可以修改readCount的互斥信号量                    rmutex.acquire();                      readCount--;                     //释放信号量                    rmutex.release();                    //当readCount==0时说明,所有读线程不再对共享资源进行操作了,则释放互斥信号量                    if(readCount==0)                    //释放信号量                     wmutex.release();                    //将cpu调度权让给其他读线程,但操作不一定成功                      Thread.yield();                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }              }            }        });      }    //创建3个写线程        for(int i=0;i<3;i++){            es.execute(new Runnable(){                @Override                public void run() {                 while(!Thread.interrupted()){                       try {                        //获取可以进行IO操作的互斥信号量,防止其他读写线程对临界资源进行操作,如果获取不到,则等待                        wmutex.acquire();                                   //进行IO 写操作                        //同样便于简单明了,这里只输出打印                        System.out.println(Thread.currentThread().getId()+"正在进行写操作.........");                        //修改临界资源的值                               sse++;                        //模拟IO操作所需时间                             Thread.sleep(1000);                        System.out.println("数据修改成功");                        //释放信号量,让其他的读或写线程可以竞争                         wmutex.release();                         //将cpu的调度权让给其他写线程,但操作不一定成功                          Thread.yield();                    } catch (InterruptedException e) {                        // TODO Auto-generated catch block                        e.printStackTrace();                    }                 }                }                   });        }    }}

结果分析:
我们代码中的无论读或写都不是原子操作的。
这里写图片描述
有上图可以看出读进程之间是不互斥的,可以并发访问。
这里写图片描述
有上图可以看出,读进程和写进程之间是互斥的,写进程和写进程之间也是互斥的。

原创粉丝点击