`
king_tt
  • 浏览: 2110693 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java 并发专题 : Semaphore 实现 互斥 与 连接池

 
阅读更多

继续并发方面的知识。今天介绍Semaphore,同样在java.util.concurrent包下。

本来准备通过例子,从自己实现到最后使用并发工具实现,但是貌似效果并不是很好,有点太啰嗦的感觉,所有准备直入主题。

介绍:Semaphore中管理着一组虚拟的许可,许可的初始数量可通过构造函数来指定【new Semaphore(1);】,执行操作时可以首先获得许可【semaphore.acquire();】,并在使用后释放许可【semaphore.release();】。如果没有许可,那么acquire方法将会一直阻塞直到有许可(或者直到被终端或者操作超时)。

作用:可以用来控制同时访问某个特定资源的操作数量,或者某个操作的数量。

下面使用Semaphore实现两个例子:

1、互斥

大家都学过操作系统,都知道互斥的概念,比较简单的互斥实现,比如PV操作,判断资源,然后忙等实现互斥;上一篇博客也说过,忙等对CPU的消耗巨大,下面我们通过Semaphore来实现一个比较好的互斥操作:

假设我们公司只有一台打印机,我们需要对这台打印机的打印操作进行互斥控制:

package com.zhy.concurrency.semaphore;

import java.util.concurrent.Semaphore;

/**
 * 使用信号量机制,实现互斥访问打印机
 * 
 * @author zhy
 * 
 */
public class MutexPrint
{

	/**
	 * 定义初始值为1的信号量
	 */
	private final Semaphore semaphore = new Semaphore(1);

	/**
	 * 模拟打印操作
	 * @param str
	 * @throws InterruptedException
	 */
	public void print(String str) throws InterruptedException
	{
		//请求许可
		semaphore.acquire();
		
		System.out.println(Thread.currentThread().getName()+" enter ...");
		Thread.sleep(1000);
		System.out.println(Thread.currentThread().getName() + "正在打印 ..." + str);
		System.out.println(Thread.currentThread().getName()+" out ...");
		//释放许可
		semaphore.release();
	}

	public static void main(String[] args)
	{
		final MutexPrint print = new MutexPrint();

		/**
		 * 开启10个线程,抢占打印机
		 */
		for (int i = 0; i < 10; i++)
		{
			new Thread()
			{
				public void run()
				{
					try
					{
						print.print("helloworld");
					} catch (InterruptedException e)
					{
						e.printStackTrace();
					}
				};
			}.start();
		}

	}

}

输出结果:

Thread-1 enter ...
Thread-1正在打印 ...helloworld
Thread-1 out ...
Thread-2 enter ...
Thread-2正在打印 ...helloworld
Thread-2 out ...
Thread-0 enter ...
Thread-0正在打印 ...helloworld
Thread-0 out ...
Thread-3 enter ...
Thread-3正在打印 ...helloworld
Thread-3 out ...

通过初始值为1的Semaphore,很好的实现了资源的互斥访问。

2、连接池的模拟实现

在项目中处理高并发时,一般数据库都会使用数据库连接池,假设现在数据库连接池最大连接数为10,当10个连接都分配出去以后,现在有用户继续请求连接,可能的处理:

a、手动抛出异常,用户界面显示,服务器忙,稍后再试

b、阻塞,等待其他连接的释放

从用户体验上来说,更好的选择当然是阻塞,等待其他连接的释放,用户只会觉得稍微慢了一点,并不影响他的操作。下面使用Semaphore模拟实现一个数据库连接池:

package com.zhy.concurrency.semaphore;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Semaphore;
/**
 * 使用Semaphore模拟数据库链接池的使用
 * @author zhy
 *
 */
public class ConnectPool
{
	private final List<Conn> pool = new ArrayList<Conn>(3);
	private final Semaphore semaphore = new Semaphore(3);

	/**
	 * 初始化分配3个连接
	 */
	public ConnectPool()
	{
		pool.add(new Conn());
		pool.add(new Conn());
		pool.add(new Conn());
	}

	/**
	 * 请求分配连接
	 * @return
	 * @throws InterruptedException
	 */
	public Conn getConn() throws InterruptedException
	{
		semaphore.acquire();
		Conn c = null  ;
		synchronized (pool)
		{
			c = pool.remove(0);
		}
		System.out.println(Thread.currentThread().getName()+" get a conn " + c);
		return c ;
	}
	
	/**
	 * 释放连接
	 * @param c
	 */
	public void release(Conn c)
	{
		pool.add(c);
		System.out.println(Thread.currentThread().getName()+" release a conn " + c);
		semaphore.release();
	}

	public static void main(String[] args)
	{

		final ConnectPool pool = new ConnectPool();
		
		/**
		 * 第一个线程占用1个连接3秒
		 */
		new Thread()
		{
			public void run()
			{
				try
				{
					Conn c = pool.getConn();
					Thread.sleep(3000);
					pool.release(c);
				} catch (InterruptedException e)
				{
					e.printStackTrace();
				}
			};
		}.start();
		/**
		 * 开启3个线程请求分配连接
		 */
		for (int i = 0; i < 3; i++)
		{
			new Thread()
			{
				public void run()
				{
					try
					{
						Conn c = pool.getConn();
					} catch (InterruptedException e)
					{
						e.printStackTrace();
					}
				};
			}.start();
		}

	}

	private class Conn
	{
	}

}

Thread-0 get a conn com.zhy.concurrency.semaphore.ConnectPool$Conn@12b6651
Thread-2 get a conn com.zhy.concurrency.semaphore.ConnectPool$Conn@e53108
Thread-1 get a conn com.zhy.concurrency.semaphore.ConnectPool$Conn@1888759
Thread-0 release a conn com.zhy.concurrency.semaphore.ConnectPool$Conn@12b6651
Thread-3 get a conn com.zhy.concurrency.semaphore.ConnectPool$Conn@12b6651
我们测试时,让Thread-0持有一个连接3秒,然后瞬间让3个线程再去请求分配连接,造成Thread-3一直等到Thread-0对连接的释放,然后获得连接。


通过两个例子,基本已经了解了Semaphore的用法,这里的线程池例子只是为了说明Semaphore的用法,真实的实现代码比这复杂的多,而且可能也不会直接用Semaphore。


好了,之后会继续Java并发的博客。

分享到:
评论

相关推荐

    mutex和semaphore互斥程序实例

    mutex和semaphore互斥程序实例

    Java并发编程:CountDownLatch与CyclicBarrier和Semaphore的实例详解

    主要介绍了Java并发编程:CountDownLatch与CyclicBarrier和Semaphore的实例详解的相关资料,需要的朋友可以参考下

    龙果java并发编程完整视频

    第34节实战:简易数据连接池00:24:53分钟 | 第35节线程之间通信之join应用与实现原理剖析00:10:17分钟 | 第36节ThreadLocal 使用及实现原理00:17:41分钟 | 第37节并发工具类CountDownLatch详解00:22:04分钟 | 第...

    java并发之Semaphore信号量.md

    Semaphore是计数信号量。Semaphore管理一系列许可证。每个acquire方法阻塞,直到有一个许可证可以获得然后拿走一个许可证;每个release方法增加一个许可证,这可能会释放一个阻塞的acquire方法。然而,其实并没有...

    Java并发编程原理与实战

    实战:简易数据连接池.mp4 线程之间通信之join应用与实现原理剖析.mp4 ThreadLocal 使用及实现原理.mp4 并发工具类CountDownLatch详解.mp4 并发工具类CyclicBarrier 详解.mp4 并发工具类Semaphore详解.mp4 并发工具...

    龙果 java并发编程原理实战

    第34节实战:简易数据连接池00:24:53分钟 | 第35节线程之间通信之join应用与实现原理剖析00:10:17分钟 | 第36节ThreadLocal 使用及实现原理00:17:41分钟 | 第37节并发工具类CountDownLatch详解00:22:04分钟 | 第...

    java并发工具类(CountDownLatch+Semaphore+Exchanger)

    java并发工具类(CountDownLatch+Semaphore+Exchanger);java并发工具类(CountDownLatch+Semaphore+Exchanger);java并发工具类(CountDownLatch+Semaphore+Exchanger);java并发工具类(CountDownLatch+...

    Java并发系列之Semaphore源码分析

    主要为大家详细介绍了Java并发系列之Semaphore源码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    Java 并发编程原理与实战视频

    第34节实战:简易数据连接池00:24:53分钟 | 第35节线程之间通信之join应用与实现原理剖析00:10:17分钟 | 第36节ThreadLocal 使用及实现原理00:17:41分钟 | 第37节并发工具类CountDownLatch详解00:22:04分钟 | 第...

    Java并发编程之Semaphore(信号量)详解及实例

    主要介绍了Java并发编程之Semaphore(信号量)详解及实例的相关资料,需要的朋友可以参考下

    java并发编程

    第34节实战:简易数据连接池00:24:53分钟 | 第35节线程之间通信之join应用与实现原理剖析00:10:17分钟 | 第36节ThreadLocal 使用及实现原理00:17:41分钟 | 第37节并发工具类CountDownLatch详解00:22:04分钟 | 第...

    java并发核心Semaphore 的使用思路.docx

    Semaphore 是 synchronized 的加强版,作用是控制线程的并发数量。就这一点而言,单纯的synchronized 关键字是实现不了的。 直接看例子吧,这个例子包含3个类,一个是线程类,一个是 Semaphore 关键代码类,一个类是...

    Java并发编程基础.pdf

    Java并发编程基础主要包括以下几个核心方面: ...并发工具类:掌握Java并发包java.util.concurrent中提供的各种工具类,如CountDownLatch、CyclicBarrier、Semaphore等,它们简化了并发编程的复杂性。

    Java并发编程学习笔记

    7、并发工具类CountDownLatch 、CyclicBarrier和Semaphore底层实现原理 8、线程池原理和如何使用线程池 9、ThreadLocal 为什么会内存泄漏 10、Volatile底层实现原理 11、AQS源码分析 12、CAS原理分析和使用场景 13、...

    java并发工具包 java.util.concurrent中文版用户指南pdf

    1. java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...

    多线程代码 经典线程同步互斥问题 生产者消费者问题

    a: 创建一个线程 b: 创建多个线程 c: 多线程访问同一资源 d: 经典线程同步互斥问题 e: 使用关键段解决子线程互斥问题 f: 利用事件实现线程同步问题 ...I: 信号量 semaphore 解决线程同步问题

    java并发工具包详解

    1. java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...

    docs:Semaphore 2.0文档

    docs:Semaphore 2.0文档

Global site tag (gtag.js) - Google Analytics