Java高并发编程中Semaphore的使用及详细介绍-刘宇

作者:刘宇
CSDN博客地址:https://blog.csdn.net/liuyu973971883
有部分资料参考,如有侵权,请联系删除。如有不正确的地方,烦请指正,谢谢。

一、什么是Semaphore?

Semaphore 是 synchronized 的加强版,可以控制线程的并发数量,而单纯的synchronized是无法做到这一点的。例如,实现一个文件允许的并发访问数。

二、常用方法

1、构造函数

  • permits:许可数量
  • fair:是否公平,如果是公平的则按照等待队列中的顺序获取,反之不一定;,不公平比公平的效率通常要高
//构造函数1,初始化可用许可数量,默认不公平
public Semaphore(int permits)
//构造函数2
public Semaphore(int permits, boolean fair)

2、acquire方法

  • 从此信号量中获取许可,可以被打断
//获取一个许可,在提供一个许可前一直将线程阻塞,除非线程被中断。
public void acquire() throws InterruptedException
//获取permits个许可,在提供许可前一直将线程阻塞,除非线程被中断。
public void acquire(int permits) throws InterruptedException

3、release方法

  • 释放许可
    注:如果释放的比获取的许可多,那么总的许可也会增加,所有一定要拿多少释放多少。
//释放一个许可。
public void release()
//释放permits个许可。
public void release(int permits)

4、acquireUninterruptibly方法

  • 获取许可,不可以被打断
//获取一个许可。
public void acquireUninterruptibly()
//获取permits个许可。
public void acquireUninterruptibly(int permits)

5、getQueueLength方法

  • 获取有多少个线程处于等待队列中
//获取等待队列长度。
public final int getQueueLength()

6、availablePermits方法

  • 获取当前有多少个可用许可
//获取当前可以许可数
public int availablePermits()

7、hasQueuedThreads方法

  • 判断是否由线程处于等待状态
//判断是否由线程处于等待状态
public final boolean hasQueuedThreads()

8、getQueuedThreads方法

  • 获取等待许可队列中的线程
  • 虽然他是protected保护的,但是我们可以通过自定义一个类来继承它来获取到
//获取等待许可队列中的线程
protected Collection<Thread> getQueuedThreads()

9、tryAcquire方法

  • 尝试获取许可,如果没有获取到直接返回,返回值为boolean
//尝试获取1个许可
public boolean tryAcquire()
//尝试在特定时间内获取1个许可,可中断
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException
//尝试获取permits个许可
public boolean tryAcquire(int permits)
//尝试在特定时间内获取permits个许可,可中断
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException

三、利用Semaphore自定义锁

package com.brycen.concurrency03.semaphore;

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

public class SemaphoreExample1 {
	public static void main(String[] args) {
		final MyLock myLock = new MyLock();
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+" is running");
					myLock.lock();
					System.out.println(Thread.currentThread().getName()+" get the lock");
					TimeUnit.SECONDS.sleep(5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					myLock.unLock();
				}
				System.out.println(Thread.currentThread().getName()+" release lock");
			}
		}).start();
		new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+" is running");
					myLock.lock();
					System.out.println(Thread.currentThread().getName()+" get the lock");
					TimeUnit.SECONDS.sleep(5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					myLock.unLock();
				}
				System.out.println(Thread.currentThread().getName()+" release lock");
			}
		}).start();
	}
	static class MyLock{
		//实例化semaphore对象,设置1个许可
		final Semaphore semaphore = new Semaphore(1);
		public void lock() throws InterruptedException {
			//获取一个许可
			semaphore.acquire();
		}
		public void unLock() {
			//释放一个许可
			semaphore.release();
		}
	}
}

运行结果:

Thread-0 is running
Thread-1 is running
Thread-0 get the lock
Thread-0 release lock
Thread-1 get the lock
Thread-1 release lock

四、简单案例

1、可打断的acquire

package com.brycen.concurrency03.semaphore;

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

public class SemaphoreExample2 {
	public static void main(String[] args) throws InterruptedException {
		final Semaphore semaphore = new Semaphore(2);
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+" is running");
					//获取一个许可
					semaphore.acquire();
					System.out.println(Thread.currentThread().getName()+" get the permits");
					TimeUnit.SECONDS.sleep(5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					//释放一个许可
					semaphore.release();
				}
				System.out.println(Thread.currentThread().getName()+" finish");
			}
		});
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+" is running");
					//获取一个许可
					semaphore.acquire();
					System.out.println(Thread.currentThread().getName()+" get the permits");
					TimeUnit.SECONDS.sleep(5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					//释放一个许可
					semaphore.release();
				}
				System.out.println(Thread.currentThread().getName()+" finish");
			}
		});
		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+" is running");
					//获取一个许可
					semaphore.acquire();
					System.out.println(Thread.currentThread().getName()+" get the permits");
				} catch (InterruptedException e) {
					e.printStackTrace();
				} finally {
					//释放一个许可
					semaphore.release();
				}
				System.out.println(Thread.currentThread().getName()+" finish");
			}
		});
		
		t1.start();
		TimeUnit.MILLISECONDS.sleep(50);
		t2.start();
		//进行休眠,确保T1、T2获取到许可
		TimeUnit.MILLISECONDS.sleep(50);
		t3.start();
		//进行休眠,确保T3执行到acquire方法
		TimeUnit.MILLISECONDS.sleep(50);
		//将T3线程进行打断
		t3.interrupt();
	}
}

输出结果:

Thread-0 is running
Thread-0 get the permits
Thread-1 is running
Thread-1 get the permits
Thread-2 is running
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1302)
	at java.util.concurrent.Semaphore.acquire(Semaphore.java:312)
	at com.brycen.concurrency03.semaphore.SemaphoreExample2$3.run(SemaphoreExample2.java:52)
	at java.lang.Thread.run(Thread.java:745)
Thread-2 finish
Thread-0 finish
Thread-1 finish

2、不可打断的acquire、获取可用许可、获取等待队列的大小

package com.brycen.concurrency03.semaphore;

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

public class SemaphoreExample3 {
	public static void main(String[] args) throws InterruptedException {
		final Semaphore semaphore = new Semaphore(2);
		
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+" is running");
					//获取一个许可
					semaphore.acquireUninterruptibly();
					System.out.println(Thread.currentThread().getName()+" get the permits");
					TimeUnit.SECONDS.sleep(5);
				}catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} finally {
					//释放一个许可
					semaphore.release();
				}
				System.out.println(Thread.currentThread().getName()+" finish");
			}
		});
		Thread t2 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+" is running");
					//获取一个许可
					semaphore.acquireUninterruptibly();
					System.out.println(Thread.currentThread().getName()+" get the permits");
					TimeUnit.SECONDS.sleep(5);
				}catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} finally {
					//释放一个许可
					semaphore.release();
				}
				System.out.println(Thread.currentThread().getName()+" finish");
			}
		});
		Thread t3 = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					System.out.println(Thread.currentThread().getName()+" is running");
					//获取一个许可
					semaphore.acquireUninterruptibly();
					System.out.println(Thread.currentThread().getName()+" get the permits");
				} finally {
					//释放一个许可
					semaphore.release();
				}
				System.out.println(Thread.currentThread().getName()+" finish");
			}
		});
		
		t1.start();
		TimeUnit.MILLISECONDS.sleep(50);
		//获取当前可用许可
		System.out.println("当前可用许可:"+semaphore.availablePermits());
		//获取当前等待队列数
		System.out.println("当前等待队列数:"+semaphore.getQueueLength());
		
		t2.start();
		//进行休眠,确保T1、T2获取到许可
		TimeUnit.MILLISECONDS.sleep(50);
		//获取当前可用许可
		System.out.println("当前可用许可:"+semaphore.availablePermits());
		//获取当前等待队列数
		System.out.println("当前等待队列数:"+semaphore.getQueueLength());
		
		t3.start();
		//进行休眠,确保t3进入acquireUninterruptibly方法
		TimeUnit.MILLISECONDS.sleep(50);
		//将T3线程进行打断,此处无效,因为我们调用的是acquireUninterruptibly
		t3.interrupt();
		//获取当前可用许可
		System.out.println("当前可用许可:"+semaphore.availablePermits());
		//获取当前等待队列数
		System.out.println("当前等待队列数:"+semaphore.getQueueLength());
	}
}

输出结果:

Thread-0 is running
Thread-0 get the permits
当前可用许可:1
当前等待队列数:0
Thread-1 is running
Thread-1 get the permits
当前可用许可:0
当前等待队列数:0
Thread-2 is running
当前可用许可:0
当前等待队列数:1
Thread-0 finish
Thread-2 get the permits
Thread-2 finish
Thread-1 finish
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值