`

Java多线程高并发高级篇(一)-信号量semaphore

 
阅读更多

多线程高并发篇终于到了高级篇。基础篇和进阶篇主要讲了线程的相关内容以及一些原理分析,最最重要的就是JMM和AQS(AbstractQueuedSynchronizer ),理解了这两个基础,高并发涉及的内容就差不多了。高级篇中涉及一些常用的并发工具类和框架。

信号量,用个很形象的例子来说,就比如我们的安检限行,一次允许通过几个人,当看见安检员的NO PASS的牌子时,就等着吧。

类似的,信号量也需要设置准入数。我们看下源码中信号量的构造方法。在信号量的构造方法中,有两个构造方法。

 

/**
     * 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);
    }

    /**
     * Creates a {@code Semaphore} with the given number of
     * permits and the given 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.
     * @param fair {@code true} if this semaphore will guarantee
     *        first-in first-out granting of permits under contention,
     *        else {@code false}
     */
    public Semaphore(int permits, boolean fair) {
        sync = (fair)? new FairSync(permits) : new NonfairSync(permits);
    }

 从构造方法中我们可以看出,信号量的准入数是必传的(准入数规定了一次可执行的线程数),默认使用的是非公平的队列同步器(当然可以根据第二个去设置使用公平的队列同步器)。

 

1.常用的几个主要方法

我们直接看源码。

/**
     * Acquires a permit from this semaphore, blocking until one is
     * available, or the thread is {@linkplain Thread#interrupt interrupted}.
     *
     * <p>Acquires a permit, if one is available and returns immediately,
     * reducing the number of available permits by one.
     *
     * <p>If no permit is available then the current thread becomes
     * disabled for thread scheduling purposes and lies dormant until
     * one of two things happens:
     * <ul>
     * <li>Some other thread invokes the {@link #release} method for this
     * semaphore and the current thread is next to be assigned a permit; or
     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
     * the current thread.
     * </ul>
     *
     * <p>If the current thread:
     * <ul>
     * <li>has its interrupted status set on entry to this method; or
     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
     * for a permit,
     * </ul>
     * then {@link InterruptedException} is thrown and the current thread's
     * interrupted status is cleared.
     *
     * @throws InterruptedException if the current thread is interrupted
     */
    public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

    /**
     * Acquires a permit from this semaphore, blocking until one is
     * available.
     *
     * <p>Acquires a permit, if one is available and returns immediately,
     * reducing the number of available permits by one.
     *
     * <p>If no permit is available then the current thread becomes
     * disabled for thread scheduling purposes and lies dormant until
     * some other thread invokes the {@link #release} method for this
     * semaphore and the current thread is next to be assigned a permit.
     *
     * <p>If the current thread is {@linkplain Thread#interrupt interrupted}
     * while waiting for a permit then it will continue to wait, but the
     * time at which the thread is assigned a permit may change compared to
     * the time it would have received the permit had no interruption
     * occurred.  When the thread does return from this method its interrupt
     * status will be set.
     */
    public void acquireUninterruptibly() {
        sync.acquireShared(1);
    }

    /**
     * Acquires a permit from this semaphore, only if one is available at the
     * time of invocation.
     *
     * <p>Acquires a permit, if one is available and returns immediately,
     * with the value {@code true},
     * reducing the number of available permits by one.
     *
     * <p>If no permit is available then this method will return
     * immediately with the value {@code false}.
     *
     * <p>Even when this semaphore has been set to use a
     * fair ordering policy, a call to {@code tryAcquire()} <em>will</em>
     * immediately acquire a permit if one is available, whether or not
     * other threads are currently waiting.
     * This &quot;barging&quot; behavior can be useful in certain
     * circumstances, even though it breaks fairness. If you want to honor
     * the fairness setting, then use
     * {@link #tryAcquire(long, TimeUnit) tryAcquire(0, TimeUnit.SECONDS) }
     * which is almost equivalent (it also detects interruption).
     *
     * @return {@code true} if a permit was acquired and {@code false}
     *         otherwise
     */
    public boolean tryAcquire() {
        return sync.nonfairTryAcquireShared(1) >= 0;
    }

    /**
     * Acquires a permit from this semaphore, if one becomes available
     * within the given waiting time and the current thread has not
     * been {@linkplain Thread#interrupt interrupted}.
     *
     * <p>Acquires a permit, if one is available and returns immediately,
     * with the value {@code true},
     * reducing the number of available permits by one.
     *
     * <p>If no permit is available then the current thread becomes
     * disabled for thread scheduling purposes and lies dormant until
     * one of three things happens:
     * <ul>
     * <li>Some other thread invokes the {@link #release} method for this
     * semaphore and the current thread is next to be assigned a permit; or
     * <li>Some other thread {@linkplain Thread#interrupt interrupts}
     * the current thread; or
     * <li>The specified waiting time elapses.
     * </ul>
     *
     * <p>If a permit is acquired then the value {@code true} is returned.
     *
     * <p>If the current thread:
     * <ul>
     * <li>has its interrupted status set on entry to this method; or
     * <li>is {@linkplain Thread#interrupt interrupted} while waiting
     * to acquire a permit,
     * </ul>
     * then {@link InterruptedException} is thrown and the current thread's
     * interrupted status is cleared.
     *
     * <p>If the specified waiting time elapses then the value {@code false}
     * is returned.  If the time is less than or equal to zero, the method
     * will not wait at all.
     *
     * @param timeout the maximum time to wait for a permit
     * @param unit the time unit of the {@code timeout} argument
     * @return {@code true} if a permit was acquired and {@code false}
     *         if the waiting time elapsed before a permit was acquired
     * @throws InterruptedException if the current thread is interrupted
     */
    public boolean tryAcquire(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

    /**
     * Releases a permit, returning it to the semaphore.
     *
     * <p>Releases a permit, increasing the number of available permits by
     * one.  If any threads are trying to acquire a permit, then one is
     * selected and given the permit that was just released.  That thread
     * is (re)enabled for thread scheduling purposes.
     *
     * <p>There is no requirement that a thread that releases a permit must
     * have acquired that permit by calling {@link #acquire}.
     * Correct usage of a semaphore is established by programming convention
     * in the application.
     */
    public void release() {
        sync.releaseShared(1);
    }

 在信号量类的方法中,实现原理就是AQS,因此请参考AQS相关帖子内容。

 

我们只介绍下功能。

①acquire():该方法获取一个准入许可,若无法获得,线程等待,直到有线程释放一个许可或者当前线程被中断,这也表达了另外一层意思--该方法是可以响应中断的。

②acquireUninterruptibly():该方法获取一个准入许可,若无法获得,线程等待,直到有线程释放一个许可,不同的是该方法不响应中断。

③tryAcquire():尝试获取一个许可,如果成功,返回true,如果失败,返回false,并且会立即返回,不等待。

tryAcquire(long timeout, TimeUnit unit):在给定的时间内尝试获取一个许可,如果成功,返回true,如果失败,返回false。

release():释放当前线程占用的许可,供其他等待许可的线程使用。

 

举例:

public class SemaphoreDemo implements Runnable {
	final Semaphore semp = new Semaphore(5);
	@Override
	public void run() {
		try {
			semp.acquire();
			//模拟处理业务逻辑
			Thread.sleep(2000);
			System.out.println(Thread.currentThread().getId()+" done!");
			semp.release();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		ExecutorService exce = Executors.newFixedThreadPool(20);
		final SemaphoreDemo demo = new SemaphoreDemo();
		for (int i = 0; i < 20; i++) {
			exce.submit(demo);
		}
		
	}

}

 从执行结果我们可以看到,系统以5个线程一组为单位,依次输出,也就是说同时只允许5个线程同时进入模拟业务逻辑处。这里要注意,如果发生信号泄露(就是在申请了准入许可后,没有释放),那么可用的准入许可越来越少,直至都被占用。

分享到:
评论

相关推荐

    Java多线程实战精讲-带你一次搞明白Java多线程高并发

    Java多线程实战精讲是Java开发者必备的技能之一,特别是在处理高并发场景时,它的重要性不言而喻。本文将深入探讨Java多线程的相关知识点,帮助你全面理解并掌握这一核心概念。 1. **线程基础** - **线程定义**:...

    Java 模拟线程并发

    最后,Java并发库还包含了很多其他有用的工具,如Semaphore(信号量)用于控制同时访问特定资源的线程数量,CyclicBarrier(循环屏障)和CountDownLatch(计数器门锁)用于多线程间的协作,以及Lock接口及其实现如...

    JAVA线程高级-线程按序交替执行

    - JUC包含了许多高级并发组件,如`Semaphore`信号量、`CyclicBarrier`回环栅栏、`CountDownLatch`倒计时器和`Exchanger`交换器等,它们可以帮助控制线程的执行顺序。 - `Semaphore`可以限制同时访问特定资源的线程...

    Java多线程编程实战指南-核心篇

    《Java多线程编程实战指南-...通过《Java多线程编程实战指南-核心篇》,你可以深入了解Java并发编程的各个方面,提升在高并发场景下的编程能力。书中的案例和练习将帮助你更好地掌握理论知识,并将其应用于实际项目中。

    人工智能-项目实践-多线程-Java多线程高并发实例.zip

    通过分析和运行这些代码,你将能够更深入地理解Java多线程在高并发场景下的实际运用,从而在你的人工智能项目中实现更高效、更稳定的数据处理。 总之,这个项目实例旨在帮助开发者掌握Java多线程技术,提升处理高...

    张孝祥Java多线程与并发库高级应用视频教程练习代码

    本教程的焦点在于“张孝祥Java多线程与并发库高级应用视频教程”的实践代码,旨在帮助开发者深入理解并熟练掌握这些关键概念。 首先,我们要明确多线程的概念。在单处理器系统中,多线程允许程序同时执行多个任务,...

    多线程,高并发.zip

    在IT领域,多线程和高并发是两个关键概念,特别是在Java编程中,它们对于构建高效、可扩展的系统至关重要。下面将详细解释这两个概念及其在Java中的实现和应用。 多线程是指在一个应用程序中同时运行多个独立的执行...

    多线程 高并发

    在IT领域,多线程和高并发是两个关键的概念,特别是在服务器端开发、分布式系统以及高性能计算中。这里,我们主要探讨的是如何通过编写多线程并发程序来优化应用程序的性能,提高系统的处理能力。 首先,多线程是指...

    Java 多线程与并发(2-26)Java 并发 - 线程基础.pdf

    Java多线程与并发是Java编程中至关重要的一个领域,特别是在构建高性能、高并发的应用时。线程基础是理解并发编程的关键,它涉及到线程的状态转换、创建与使用方式、同步与协作机制等方面。 线程有五种基本状态: 1...

    Java并发编程(23)并发新特性-信号量Semaphor

    信号量(Semaphore)是Java并发库中的一种工具类,它提供了一种控制多个线程对共享资源访问的方式,从而实现高级别的同步。在Java 5引入并发包`java.util.concurrent`后,信号量作为`Semaphore`类被添加,成为并发...

    java多线程并发实战和源码

    Java多线程并发实战与源码分析是Java开发中至关重要的一部分,它涉及到程序性能优化、系统资源高效利用以及复杂逻辑的正确同步。本书主要聚焦于Java多线程的基础理论和实际应用,虽然书中实例和源码相对较少,但仍然...

    汪文君JAVA多线程编程实战(完整不加密)

    《汪文君JAVA多线程编程实战》是一本专注于Java多线程编程的实战教程,由知名讲师汪文君倾力打造。这本书旨在帮助Java开发者深入理解和熟练掌握多线程编程技术,提升软件开发的效率和质量。在Java平台中,多线程是...

    Java多线程编程总结

    ### Java多线程编程总结 #### 一、Java线程:概念与原理 1. **操作系统中线程和进程的概念** - 当前的操作系统通常为多任务操作系统,多线程是实现多任务的一种手段。 - **进程**:指内存中运行的应用程序,每个...

    Java多线程运算集合

    #### 一、Java多线程概念与原理 - **操作系统中的线程与进程**: - **进程**:指的是一个正在运行的应用程序,每个进程都拥有独立的内存空间。 - **线程**:是进程中的一个执行单元,一个进程中可以包含多个线程...

    Java 多线程与并发(10-26)-JUC锁- 锁核心类AQS详解.pdf

    Java中的多线程与并发编程是高级编程技术的重要组成部分,对于理解并实现高效的多任务处理至关重要。Java并发包(java.util.concurrent,简称JUC)提供了一系列工具和类库来帮助开发者简化并发编程的工作。其中,...

    java面试多线程高并发相关回家技巧(超经典)

    本文将围绕“Java面试多线程高并发相关回家技巧”这一主题,深入探讨相关概念、原理以及面试中可能遇到的问题,帮助你做好充分准备。 一、线程基础 1. **线程的创建**:Java提供了两种创建线程的方式,一是通过实现...

    java线程与并发编程实践

    Java提供了一系列并发工具类,如Semaphore(信号量)、CyclicBarrier(循环屏障)、CountDownLatch(计数器门锁)和Exchanger(交换器),它们用于控制线程间访问资源的顺序和数量,协调多个线程间的操作。...

    java多线程

    Java多线程是一种允许多个线程在单个Java程序中并发执行的机制,它允许程序更加高效地利用系统资源,并提高应用程序的响应能力。在Java中,线程是程序中能够并发执行的一个代码块,可以独立控制执行流程和访问共享...

    java多线程文件传输

    Java多线程文件传输是Java编程中一个重要的实践领域,特别是在大数据处理、网络通信和分布式系统中。在Java中,多线程可以提高程序的执行效率,尤其在处理并发任务时,如大文件的上传、下载和传输。下面将详细探讨...

    JAVA多线程模式高清版+DEMO

    Java多线程是Java编程中的一个核心概念,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,实现多线程有两种主要方式:通过继承`Thread`类或者实现`Runnable`接口。这个压缩包文件"JAVA多...

Global site tag (gtag.js) - Google Analytics