Java中怎么控制线程访问资源的数量

在API中是这样来描述Semaphore 的

Semaphore 通常用于限制可以访问某些资源(物理或逻辑的)的线程数目。

一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个
release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。

例如,下面的类使用信号量控制线程并发的数量

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

public class TestSemaphore {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
         ExecutorService pool =  Executors.newCachedThreadPool();
         final Semaphore sp = new Semaphore(3,true);
         for(int i=0;i<10;i++){
             Runnable runnable = new Runnable() {

				@Override
				public void run() {

                	   try {
						sp.acquire();
					} catch (InterruptedException e) {
   						e.printStackTrace();
                   }
                	   System.out.println(sp.availablePermits());
                   System.out.println("线程  "+ Thread.currentThread().getName() +"进入,已有"+ (3-sp.availablePermits())+ "并发") ;
            	   try {
					Thread.sleep((long) (Math.random()*3000));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
            	   System.out.println("线程  "+Thread.currentThread().getName() +"即将离开 " );
            	   sp.release();
            	   System.out.println("线程  "+Thread.currentThread().getName() +"离开 ,已有"+ (3-sp.availablePermits()) + "并发");
				}
			};
			pool.execute(runnable);
         }
	}

}

再例如可以通过信号量来控制线程访问资源:

import java.util.concurrent.Semaphore;

public class DownloadThread {
	private static int in_index = 0;
	private static int out_index = 0;
	private static int buffer_count = 100;
	public static boolean g_downloadComplete;
	private static Semaphore g_seFull = new Semaphore(0);
	private static Semaphore g_seEmpty = new Semaphore(buffer_count);
	 public static boolean getBlockFromNet(int in_index) {
		  int i = 0;
		  while (i < 10000)
		   i++;
		  if (in_index < buffer_count - 1)
		   return false;
		  else
		   return true;
		 }
		 public static void writeBlockToDisk(int out_index) {
		  int i = 0;
		  while (i < 100000)
		   i++;
		 }

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		 g_downloadComplete = false;
		  Thread threadA = new Thread() {
		   public void run() {
		    proA();
		   }
		  };
		  Thread threadB = new Thread() {
		   public void run() {
		    proB();
		   }
		  };
		  threadB.start();
		  threadA.start();
		 }

	public static void proA(){
		 while (g_seFull.availablePermits() < buffer_count) {
			   try {
			    g_seEmpty.acquire();
			   } catch (InterruptedException e1) {
			    // TODO Auto-generated catch block
			    e1.printStackTrace();
			   }
			   g_downloadComplete = getBlockFromNet(in_index);
			   in_index = (in_index + 1) % buffer_count;
			   g_seFull.release();
			   System.out.println("download a block " + in_index);
			   if (g_downloadComplete)
			    break;
			  }
	}

	public static void proB(){
		 while (g_seEmpty.availablePermits() > 0) {
			   try {
			    g_seFull.acquire();
			   } catch (InterruptedException e1) {
			    // TODO Auto-generated catch block
			    e1.printStackTrace();
			   }
			   writeBlockToDisk(out_index);
			   out_index = (out_index + 1) % buffer_count;
			   g_seEmpty.release();
			   System.out.println("write a block " + out_index);
			   if (g_downloadComplete && out_index == in_index)
			    break;
			  }
	}

}

时间: 2024-10-14 13:08:39

Java中怎么控制线程访问资源的数量的相关文章

JAVA学习篇--ThreadLocal,Java中特殊的线程绑定机制

在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个connection连接).那么ThreadLocal是如果做到的呢?它和同步锁的不同在哪里? 是什么: 对于ThreadLocal看英文单词我们很容易理解为一个线程的本地实现,但是它并不是一个Thread,而是threadlocalvariable(线程局部变量).也许把它命名为ThreadLoc

Java中的守护线程

Java中的守护线程 Java中的守护线程与UNIX中的守护线程概念不同,UNIX中的守护线程相当于一项服务,一直运行在后台,而Java中的守护线程是这样定义的: A daemon thread is a thread, that does not prevent the JVM from exiting when the program finishes but the thread is still running. 也就是说,当程序中只有守护线程时,JVM就会自动退出,典型的守护线程就是垃

线程基础:线程(3)——JAVA中的基本线程操作(中)

(接上文<线程基础:线程(2)--JAVA中的基本线程操作(上)>) 1-4.注意synchronized关键字的使用 在前面的文章中我们主要讲解的是线程中"对象锁"的工作原理和操作方式.在讲解synchronized关键字的时候,我们还提到了synchronized关键字可以标注的位置.大家经常看到相当部分的网贴,在它们的代码示例中将synchronized关键字加载到代码的方法体上,然后告诉读者:这个操作是线程安全的.代码可能如下: /** * 这个类的class对象进

Java中的包与访问权限的控制

多人开发 在java中,可以将一个大型项目中的类分别独立出来,分门别类的存到文件里,再将这些文件一起编译运行,如此的程序代码将更易于维护. 多人开发的问题:如果多个开发人员共同开发一个项目的时候,则肯定会出现类名称相同的情况.那么这样一来就会非常麻烦. 相同的文件会出现覆盖的情况. 包的概念 package是在使用多个类或接口时,为了避免名称重复而采用的一种措施,直接在程序中加入package关键字即可. 包的定义格式: package 包名称.子包名称: package org.lxh.dem

Java-ThreadLocal,Java中特殊的线程绑定机制

在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个connection连接).那么ThreadLocal是如果做到的呢?它和同步锁的不同在哪里? 是什么: 对于ThreadLocal看英文单词我们很容易理解为一个线程的本地实现,但是它并不是一个Thread,而是threadlocalvariable(线程局部变量).也许把它命名为ThreadLoc

Java中事件分发线程(EDT)与SwingUtilities.invokeLater相关总结

前言:这篇文章严格来说不算原创,算是我对这方面知识的一点小结,素材来至其他网友.当然我在我写的C段查询工具也用到了这方面的东西,不过由于代码太多不方便用作事例,因此用了他人的素材总结一下,望理解O(∩_∩)O~ 一 Swing线程基础 一个Swing程序中一般有下面三种类型的线程:    * 初始化线程(Initial Thread)    * UI事件调度线程(EDT)    * 任务线程(Worker Thread)每个程序必须有一个main方法,这是程序的入口.该方法运行在初始化或启动线程

【Simple Java】Java中怎样创建线程安全的方法

面试问题: 下面的方法是否线程安全?怎样让它成为线程安全的方法? class MyCounter { private static int counter = 0; public static int getCount() { return counter++; } } 本篇文章将解释一个常见的面试题,该问题被谷歌和很多其它公司问起过.它涉及的相对比较初级,而不是关于怎样去设计复杂的并发程序. 首先,这个问题的答案是No,因为counter++操作不是一个原子操作,而是由多个原子操作组成. 举个

关于Java中进程和线程的详解

一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消.反映了一个程序在 一定的数据 集上运行的全部动态过程.通过进程控制块(PCB)唯一的标识某个进程.同时进程占据着相应的资源(例如包 括cpu的使用 ,轮转时间以及一些其它设备的权限).是系统进行资源分配和调度的一个独立单位. 程序和进程之间的主要区别在于: 状态         是否具有资源

Java中的守护线程和非守护线程(转载)

<什么是守护线程,什么是非守护线程> Java有两种Thread:“守护线程Daemon”(守护线程)与“用户线程User”(非守护线程). 用户线程:非守护线程包括常规的用户线程或诸如用于处理GUI事件的事件调度线程,Java虚拟机在它所有非守护线程已经离开后自动离开. 守护线程:守护线程则是用来服务用户线程的,比如说GC线程.如果没有其他用户线程在运行,那么就没有可服务对象,也就没有理由继续下去.(操作系统里面是没有所谓的守护线程的概念,只有守护进程一说,但是Java语言机制是构建在JVM