Semaphore 使用和面试注意点

正常的锁(比如lock)一般都是用来只允许一个任务访问一项资源,而*计数信号量(Semaphore)*允许最多n个任务同时访问这个资源,常常被用来做流控。

信号量在使用的过程中总结有如下几点需要注意的:

  • 想要执行必须要能通过 acquire() 相关方法获取许可证,否则就会被阻塞,见示例1
  • acquirerelease 没有绝对的先后顺序,release 可以先于 acquire 执行,且许可证的数量和初始化时么关系,见示例2
  • acquireUninterruptibly 方法相对于 acquire 方法主要是及时是耗时的操作也不会中断,必须执行完,所以一般生产环境推荐使用acquire,避免长时间占用线程
  • 在实例化的时候可以指定公平锁或者非公平锁,两者区别,见示例1:
    • 公平:即根据先来后到的顺序给阻塞队列中的线程颁发许可证
    • 非公平:给任意一个线程颁发许可证
示例1

6个雇员,只有3个坑位,所以只能最多三个人登坑

package com.demos.semaphore;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class SimpleSemaphoreTest {
    public static void main(String[] args) {
//        Semaphore pits = new Semaphore(3);
        Semaphore pits = new Semaphore(3,true); // 使用公平锁,实例化3个坑位

        new Thread(new Employee(pits, "雇员1")).start();
        new Thread(new Employee(pits, "雇员2")).start();
        new Thread(new Employee(pits, "雇员3")).start();
        new Thread(new Employee(pits, "雇员4")).start();
        new Thread(new Employee(pits, "雇员5")).start();
        new Thread(new Employee(pits, "雇员6")).start();
    }
}

class Employee implements Runnable {
    private Semaphore semaphore;
    private String name;

    public Employee(Semaphore semaphore, String name) {
        this.semaphore = semaphore;
        this.name = name;
    }

    @Override
    public void run() {
        try {
            this.semaphore.acquire();
            System.out.println(this.name + " 开始登坑...");
            TimeUnit.SECONDS.sleep(2);
            System.out.println(this.name + " 结束登坑...");
            this.semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
// 使用公平锁
雇员2 开始登坑...
雇员1 开始登坑...
雇员3 开始登坑...
雇员3 结束登坑...
雇员2 结束登坑...
雇员1 结束登坑...
雇员5 开始登坑...
雇员6 开始登坑...
雇员4 开始登坑...
雇员5 结束登坑...
雇员6 结束登坑...
雇员4 结束登坑...

// 非公平锁随机分配
雇员2 开始登坑...
雇员1 开始登坑...
雇员6 开始登坑...
雇员1 结束登坑...
雇员6 结束登坑...
雇员3 开始登坑...
雇员2 结束登坑...
雇员5 开始登坑...
雇员4 开始登坑...
雇员5 结束登坑...
雇员3 结束登坑...
雇员4 结束登坑...
示例2
package com.demos.semaphore;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class TestSemaphore2 {
    public static void main(String[] args) {
        int permitsNum = 2;
        final Semaphore semaphore = new Semaphore(permitsNum);
        try {
            System.out.println("availablePermits:" + semaphore.availablePermits());
            // 未执行acquire先执行了release
            semaphore.release(2);
            // 此时打印可用许可证是4个,表示和初始化值没关系
            System.out.println("availablePermits:" + semaphore.availablePermits() + ",semaphore.tryAcquire(4, 1, TimeUnit.SECONDS):" + semaphore.tryAcquire(4, 1, TimeUnit.SECONDS));
        } catch (Exception e) {

        }
    }
}

你可能感兴趣的:(并发编程,JAVA基础,java,多线程)