Java并发编程中级篇(二):使用Semaphore信号量进行多个资源并发控制

原创
2016/11/25 17:01
阅读数 351

上一节中我们使用了Semaphore信号量保护共享资源,但是它只能保护一个共享资源,当我们需要同时保护多个共享资源的时候,我们只需要在创建信号量的时候使用new Semaphore(int)构造方法,传入参数是你想要保护的共享资源数目。

    /**
     * Creates a {@code Semaphore} with the given number of
     * permits and nonfair fairness setting.
     *
     * @param permits the initial number of permits available.
     *        This value may be negative, in which case releases
     *        must occur before any acquires will be granted.
     */
    public Semaphore(int permits) {
        sync = new NonfairSync(permits);
    }

还是PrintQueue的例子,我们把打印队列中打印机数目增加到3台,使用一个boolean[3]数组来标记打印机是否可用,同时使用3个信号量来保证这三个打印机的并发访问控制。定义一个锁来保证更改打印机状态的时候的同步控制。获取打印机资源的时候记录打印机ID,并标记打印机处于使用状态。释放打印机资源的时候,把相应ID的打印机状态置为可用。

public class PrintQueue {
    private boolean freePrinters[];
    private Lock lockPrinters;
    private Semaphore semaphore;

    public PrintQueue() {
        this.freePrinters = new boolean[3];
        this.lockPrinters = new ReentrantLock();
        this.semaphore = new Semaphore(3);

        for (int i = 0; i < 3; i++) {
            this.freePrinters[i] = true;
        }
    }

    public void printJob(Object object) {
        try {
            semaphore.acquire();
            int assignedPrinter = getPrinter();

            long duration = (long)(Math.random() * 10);
            System.out.printf("%s: Print a Job in printer %d duration %d seconds.\n",
                    Thread.currentThread().getName(), assignedPrinter, duration);
            TimeUnit.SECONDS.sleep(duration);

            freePrinter(assignedPrinter);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }

    private int getPrinter() {
        lockPrinters.lock();
        int printNo = -1;
        try {
            for (int i = 0; i < freePrinters.length; i++) {
                if (freePrinters[i]) {
                    printNo = i;
                    freePrinters[i] = false;
                    break;
                }
            }
        } finally {
            lockPrinters.unlock();
        }
        return printNo;
    }

    private void freePrinter(int printNo) {
        lockPrinters.lock();

        try {
            freePrinters[printNo] = true;
        } finally {
            lockPrinters.unlock();
        }
    }

打印Job线程类和主方法类不变

public class Job implements Runnable{
    private PrintQueue printQueue;

    public Job(PrintQueue printQueue) {
        this.printQueue = printQueue;
    }

    @Override
    public void run() {
        System.out.printf("%s: Going to print a Job.\n", Thread.currentThread().getName());
        printQueue.printJob(new Object());
        System.out.printf("%s: The Job has been printed.\n", Thread.currentThread().getName());
    }
}
public class Main {
    public static void main(String[] args) {
        PrintQueue printQueue = new PrintQueue();

        Thread[] threads = new Thread[10];
        for (int i = 1; i < 10; i++) {
            threads[i] = new Thread(new Job(printQueue));
        }

        for (int i = 1; i < 10; i++) {
            threads[i].start();
        }
    }
}

执行查看控制台日志,你可以发现每次有三个打印Job可以执行。

Thread-0: Going to print a Job.
Thread-8: Going to print a Job.
Thread-7: Going to print a Job.
Thread-6: Going to print a Job.
Thread-5: Going to print a Job.
Thread-4: Going to print a Job.
Thread-3: Going to print a Job.
Thread-2: Going to print a Job.
Thread-1: Going to print a Job.
Thread-8: Print a Job in printer 1 duration 2 seconds.
Thread-7: Print a Job in printer 2 duration 6 seconds.
Thread-0: Print a Job in printer 0 duration 2 seconds.
Thread-0: The Job has been printed.
Thread-5: Print a Job in printer 1 duration 7 seconds.
Thread-6: Print a Job in printer 0 duration 9 seconds.
Thread-8: The Job has been printed.
Thread-7: The Job has been printed.
Thread-4: Print a Job in printer 2 duration 1 seconds.
Thread-4: The Job has been printed.
Thread-3: Print a Job in printer 2 duration 6 seconds.
Thread-5: The Job has been printed.
Thread-2: Print a Job in printer 1 duration 7 seconds.
Thread-6: The Job has been printed.
Thread-1: Print a Job in printer 0 duration 2 seconds.
Thread-3: The Job has been printed.
Thread-1: The Job has been printed.
Thread-2: The Job has been printed.

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部