Java并发编程实例--20.使用Semaphores(信号量)控制资源的并发读取

本文介绍了一种使用信号量(semaphore)控制并发访问共享资源的方法。通过一个打印队列的例子展示了如何利用信号量来实现线程间的同步,确保同一时刻只有一个线程能够访问打印队列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前面我们介绍了2种同步机制:


1)使用synchronized关键字

2)使用Lock接口及其实现类:

ReentrantLock,ReentrantReadWriteLock.ReadLock, and ReentrantReadWriteLock.WriteLock


本例中,我们将学习更高级的同步方式:semaphore (信号量)

先看下概念:

Semaphores: A semaphore is a counter that controls the access to one ormore shared resources. This mechanism is one of the basic tools of concurrent programming and is provided by most of the programming languages.

一个信号量是控制读取一个或多个共享资源的计数器。

这一机制是并发编程中提供的一种基本工具并且绝大多数编程语言都有提供。


当一个线程想去读取某个共享资源,它必须获得信号。

如果semaphore大于0,这意味着当前资源处于空闲状态,这个时候它会减1,并允许该线程读取。

否则,信号将会让该线程睡眠直到信号量再次大于0。

当线程使用完共享资源后需要释放信号量,这样其它线程方能接着获取。


PrintQueue.java

package com.dylan.thread.ch3.c01.task;

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

/**
 * This class implements the PrintQueue using a Semaphore to control the
 * access to it. 
 *
 */
public class PrintQueue {
	
	/**
	 * Semaphore to control the access to the queue
	 */
	private final Semaphore semaphore;
	
	/**
	 * Constructor of the class. Initializes the semaphore
	 */
	public PrintQueue(){
		semaphore=new Semaphore(1);
	}
	
	/**
	 * Method that simulates printing a document
	 * @param document Document to print
	 */
	public void printJob (Object document){
		try {
			// Get the access to the semaphore. If other job is printing, this
			// thread sleep until get the access to the semaphore
			semaphore.acquire();
			
			Long duration=(long)(Math.random()*10);
			System.out.printf("%s: PrintQueue: Printing a Job during %d seconds\n",Thread.currentThread().getName(),duration);
			Thread.sleep(duration);			
			TimeUnit.SECONDS.sleep(duration);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			// Free the semaphore. If there are other threads waiting for this semaphore,
			// the JVM selects one of this threads and give it the access.
			semaphore.release();			
		}
	}

}


Job.java

package com.dylan.thread.ch3.c01.task;

/**
 * This class simulates a job that send a document to print.
 *
 */
public class Job implements Runnable {

	/**
	 * Queue to print the documents
	 */
	private PrintQueue printQueue;
	
	/**
	 * Constructor of the class. Initializes the queue
	 * @param printQueue
	 */
	public Job(PrintQueue printQueue){
		this.printQueue=printQueue;
	}
	
	/**
	 * Core method of the Job. Sends the document to the print queue and waits
	 *  for its finalization
	 */
	@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 document has been printed\n",Thread.currentThread().getName());		
	}
}


Main.java

package com.dylan.thread.ch3.c01.core;


import com.dylan.thread.ch3.Job;
import com.dylan.thread.ch3.PrintQueue;

/**
 * Main class of the example.
 *
 */
public class Main {

	/**
	 * Main method of the class. Run ten jobs in parallel that
	 * send documents to the print queue at the same time.
	 */
	public static void main (String args[]){
		
		// Creates the print queue
		PrintQueue printQueue=new PrintQueue();
		
		// Creates ten Threads
		Thread thread[]=new Thread[10];
		for (int i=0; i<10; i++){
			thread[i]=new Thread(new Job(printQueue),"Thread "+i);
		}
		
		// Starts the Threads
		for (int i=0; i<10; i++){
			thread[i].start();
		}
	}

}


运行结果:

Thread 3: Going to print a job
Thread 9: Going to print a job
Thread 5: Going to print a job
Thread 7: Going to print a job
Thread 4: Going to print a job
Thread 0: Going to print a job
Thread 2: Going to print a job
Thread 1: Going to print a job
Thread 8: Going to print a job
Thread 6: Going to print a job
Thread 3: PrintQueue: Printing a Job during 2 seconds
Thread 9: PrintQueue: Printing a Job during 5 seconds
Thread 3: The document has been printed
Thread 9: The document has been printed
Thread 5: PrintQueue: Printing a Job during 9 seconds
Thread 5: The document has been printed
Thread 7: PrintQueue: Printing a Job during 7 seconds
Thread 7: The document has been printed
Thread 4: PrintQueue: Printing a Job during 9 seconds
Thread 0: PrintQueue: Printing a Job during 6 seconds
Thread 4: The document has been printed
Thread 0: The document has been printed
Thread 2: PrintQueue: Printing a Job during 5 seconds
Thread 2: The document has been printed
Thread 1: PrintQueue: Printing a Job during 1 seconds
Thread 8: PrintQueue: Printing a Job during 5 seconds
Thread 1: The document has been printed
Thread 8: The document has been printed
Thread 6: PrintQueue: Printing a Job during 3 seconds
Thread 6: The document has been printed







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值