Java进程间的同步与互斥实例(实现读者写者问题)

题目描述:

给定一个队列A[1-10][1-100000]、元素编号1-10,其中每个元素包含10万个随机数。创建若干个线程,各循环100次;其中10,100个为读线程,10,100个为更新线程。

1.    读线程每次产生随机数三元组:(i, j, k),其中i:[1-10], j: [1-100000],k[j-100000],求取指定A[i]一级数组中第j到第k个元素的均值;

2.    更新线程每次产生一对随机整数三元组 (i, j, k) 和一个随机浮点数d:(0-1),其中i: [1-10], j: [1-100000],k[j-100000],完成对A[i][j]到A[i][k]之间的所有元素进行数值更新,x = x * (1 + d)



基础知识:

读者—写者问题(Readers-Writers problem)也是一个经典的并发程序设计问题,是经常出现的一种同步问题。计算机系统中的数据(文件、记录)常被多个进程共享,但其中某些进程可能只要求读数据(称为读者Reader);另一些进程则要求修改数据(称为写者Writer)。就共享数据而言,Reader和Writer是两组并发进程共享一组数据区,通常要求满足:
(1)允许多个读者同时执行读操作;
(2)不允许读者、写者同时操作;

(3)不允许多个写者同时操作。

实现的原理:

Semaphore当前在多线程环境下被扩放使用,操作系统的信号量是个很重要的概念,在进程控制方面都有应用。Java 并发库 的Semaphore 可以很轻松完成信号量控制,Semaphore可以控制某个资源可被同时访问的个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。比如在Windows下可以设置共享文件的最大客户端访问个数。 

Semaphore实现的功能就类似厕所有5个坑,假如有10个人要上厕所,那么同时只能有多少个人去上厕所呢?同时只能有5个人能够占用,当5个人中 的任何一个人让开后,其中等待的另外5个人中又有一个人可以占用了。另外等待的5个人中可以是随机获得优先机会,也可以是按照先来后到的顺序获得机会,这取决于构造Semaphore对象时传入的参数选项。单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。

Semaphore维护了当前访问的个数,提供同步机制,控制同时访问的个数。在数据结构中链表可以保存“无限”的节点,用Semaphore可以实现有限大小的链表。另外重入锁 ReentrantLock 也可以实现该功能,但实现上要复杂些。


编程实现:

工程下载地址:http://download.csdn.net/detail/qq_24369113/9720663

ReadAndWrite.java是测试类

ReadThread.java是读线程类

WriteThread.java是写线程类

默认生成100个读线程和100个写线程,每个线程循环100次,ReadAndWrite.java中的Value数组模拟临界区资源,对其每一行设置一个锁,对每一行允许同时最多有5个读线程进行操作,或者一个写线程进行操作。


ReadThread.java

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Semaphore;

/**
 * Created by 32706 on 2016/12/24.
 */
public class ReadThread extends Thread
{
    public int id;// 读者ID

    //public  static  int readCount=0;// 读者数量
    public static Map<Integer,Integer> readCountMap=new HashMap<>();//存放每一行的读者数量
    public static Map<Integer,Semaphore> mutex=new HashMap<>();//确保在更新readCountMap的原子性



    public static void init_readthread_readcountmap()
    {
        for(int i=0;i<ReadAndWrite.Value.length;i++)
        {
            readCountMap.put(i,0);
            mutex.put(i,new Semaphore(1));
        }
    }


    public ReadThread(int id)
    {
        this.id = id;
    }

    private double get_avrage(int i,int j,int k)
    {
        double sum=0;
        for(int r=j;r<=k;r++)
            sum=ReadAndWrite.Value[i][r]+sum;

        return sum/(k-j+1);

    }

    //读者优先
    public void run()
    {
        try{
            for(int x=0;x<ReadAndWrite.execute_times;x++)
            {
                int thread_i=(int)(Math.random()*20)%10;
                int thread_j=(int) (Math.random()*200000)%100000;
                int thread_k=(int)(Math.random()*200000)%(100000-thread_j)+thread_j;
                try
                {
                    System.out.println(id+"号读线程准备读取第"+thread_i+"行的"+thread_j+"=>"+thread_k+"的数据"+"                                                "+ System.currentTimeMillis());

                    mutex.get(thread_i).acquire();
                    if (readCountMap.get(thread_i) == 0)//如果是第i行的第一个读者,那么要考虑是否有写者,没有写者,直接读,有写者,等待写者
                    {
                        if(ReadAndWrite.writeSemaphoreMap.get(thread_i).availablePermits()==0)//有人在写
                        {
                            System.out.println("有写线程在写操作,"+id+"号线程等待读===="+"                                                "+ System.currentTimeMillis());
                        }
                        ReadAndWrite.writeSemaphoreMap.get(thread_i).acquire();//上写锁

                    }
                    int  readCount=readCountMap.get(thread_i)+1;// 已经具备读的条件了,读者数量加1
                    readCountMap.put(thread_i,readCount);
                    mutex.get(thread_i).release();


                    if(ReadAndWrite.readCountSemaphoreMap.get(thread_i).availablePermits()==0)//读者过多
                    {
                        System.out.println("当前读线程过多,"+id+"号线程等待读===="+"                                                "+ System.currentTimeMillis());
                    }
                    // 等待着读
                    ReadAndWrite.readCountSemaphoreMap.get(thread_i).acquire();//如果读者过多则会等待,读者小于5则可以读

                    //可以读了
                    System.out.println(id+"号读线程正在读取数据...."+"                                                "+ System.currentTimeMillis());
                   
                    System.out.println(id+"号读线程计算结果为~~~~"+get_avrage(thread_i,thread_j,thread_k)+"                                                "+ System.currentTimeMillis());

                    mutex.get(thread_i).acquire();
                    //读完了,读者数量减少1
                    int readCounttem=readCountMap.get(thread_i)-1;
                    readCountMap.put(thread_i,readCounttem);
                    if(readCountMap.get(thread_i)==0)//没有读者了,可以写了
                    {
                        ReadAndWrite.writeSemaphoreMap.get(thread_i).release();
                    }
                    ReadAndWrite.readCountSemaphoreMap.get(thread_i).release();//释放读者信号量
                    mutex.get(thread_i).release();


                    Thread.sleep((long) (new Random().nextFloat()*1000));
                }
                catch (InterruptedException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        finally{
        ReadAndWrite.Runningthread++;
    }

    }
} 




  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值