Java编程线程间通信与信号量代码示例

1.信号量Semaphore

先说说Semaphore,Semaphore可以控制某个资源可被同时访问的个数,通过acquire()获取一个许可,如果没有就等待,而release()释放一个许可。一般用于控制并发线程数,及线程间互斥。另外重入锁ReentrantLock也可以实现该功能,但实现上要复杂些。

功能就类似厕所有5个坑,假如有10个人要上厕所,那么同时只能有多少个人去上厕所呢?同时只能有5个人能够占用,当5个人中的任何一个人让开后,其中等待的另外5个人中又有一个人可以占用了。另外等待的5个人中可以是随机获得优先机会,也可以是按照先来后到的顺序获得机会。

单个信号量的Semaphore对象可以实现互斥锁的功能,并且可以是由一个线程获得了“锁”,再由另一个线程释放“锁”,这可应用于死锁恢复的一些场合。

例子:

/**
 * @Description:
 * @param @param args
 * @return void 返回类型
 */
public static void main(String[] args) {
  // 线程池
  ExecutorService exec = Executors.newCachedThreadPool();
  // 只能5个线程同时访问
  final Semaphore semp = new Semaphore(5);
  // 模拟20个客户端访问
  for (int index = 0; index < 20; index++) {
    final int NO = index;
    Runnable run = new Runnable() {
      public void run() {
        try {
          // 获取许可
          semp.acquire();
          System.out.println("获得Accessing: " + NO);
          Thread.sleep((long) (Math.random() * 10000));
          // 访问完后,释放
          semp.release();
          System.out.println("剩余可用信号-----------------"
              + semp.availablePermits());
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    };
    exec.execute(run);
  }
  // 退出线程池
  exec.shutdown();
}

输出结果(可以想想为什么会这样输出):

获得Accessing: 1
获得Accessing: 5
获得Accessing: 2
获得Accessing: 3
获得Accessing: 0
剩余可用信号-----------------1
获得Accessing: 4
剩余可用信号-----------------1
获得Accessing: 9
剩余可用信号-----------------1
获得Accessing: 8
剩余可用信号-----------------1
获得Accessing: 6
剩余可用信号-----------------1
获得Accessing: 10
剩余可用信号-----------------1
获得Accessing: 11
剩余可用信号-----------------1
获得Accessing: 12
剩余可用信号-----------------1
获得Accessing: 13
剩余可用信号-----------------1
获得Accessing: 7
剩余可用信号-----------------1
获得Accessing: 15
剩余可用信号-----------------1
获得Accessing: 16
剩余可用信号-----------------1
获得Accessing: 17
剩余可用信号-----------------1
获得Accessing: 14
剩余可用信号-----------------1
获得Accessing: 18
剩余可用信号-----------------1
获得Accessing: 19
剩余可用信号-----------------1
剩余可用信号-----------------2
剩余可用信号-----------------3
剩余可用信号-----------------4
剩余可用信号-----------------5

2.使用PIPE作为线程间通信桥梁

Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。一进一出。先作为初步了解怎么使用。

值得注意的是该类在java.nio.channels下,说明该类属于nio方式的数据通信方式,那就使用Buffer来缓冲数据。

Pipe原理的图示:

Pipe就是个空管子,这个空管子一头可以从管子里往外读,一头可以往管子里写

操作流程:

1.首先要有一个对象往这个空管子里面写。写到哪里呢?这个空管子是有一点空间的,就在这个管子里。

写的时候就是写到管子本身包含的这段空间里的。这段空间大小是1024个字节。

2.然后另一个对象才能将这个装满了的管子里的内容读出来。

上代码

package com.jx.test;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;
public class testPipe {
	/**
   * @Description:
   * @param @param args
   * @return void 返回类型
   * @throws IOException
   */
	public static void main(String[] args) throws IOException {
		// 创建一个管道
		Pipe pipe = Pipe.open();
		final Pipe.SinkChannel psic = pipe.sink();
		// 要向管道写数据,需要访问sink通道
		final Pipe.SourceChannel psoc = pipe.source();
		// 从读取管道的数据,需要访问source通道
		Thread tPwriter = new Thread() {
			public void run() {
				try {
					System.out.println("send.....");
					// 创建一个线程,利用管道的写入口Pipe.SinkChannel类型的psic往管道里写入指定ByteBuffer的内容
					int res = psic.write(ByteBuffer
										              .wrap("Hello,Pipe!测试通讯.....".getBytes("utf-16BE")));
					System.out.println("send size:" + res);
				}
				catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		;
		Thread tPreader = new Thread() {
			public void run() {
				int bbufferSize = 1024 * 2;
				ByteBuffer bbuffer = ByteBuffer.allocate(bbufferSize);
				try {
					System.out.println("recive.....");
					// 创建一个线程,利用管道的读入口Pipe.SourceChannel类型的psoc将管道里内容读到指定的ByteBuffer中
					int res = psoc.read(bbuffer);
					//数据未
					System.out.println("recive size:"+res+" Content:" + ByteBufferToString(bbuffer));
				}
				catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		;
		tPwriter.start();
		tPreader.start();
	}
	/**
   *ByteBuffer--> String的转换函数
   */
	public static String ByteBufferToString(ByteBuffer content) {
		if (content == null || content.limit() <= 0
				        || (content.limit() == content.remaining())) {
			System.out.println("不存在或内容为空!");
			return null;
		}
		int contentSize = content.limit() - content.remaining();
		StringBuffer resultStr = new StringBuffer();
		for (int i = 0; i < contentSize; i += 2) {
			resultStr.append(content.getchar(i));
		}
		return resultStr.toString();
	}
}

总结

以上就是本文关于Java编程线程间通信与信号量代码示例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

(0)

相关推荐

  • java信号量控制线程打印顺序的示例分享

    复制代码 代码如下: import java.util.concurrent.Semaphore; public class ThreeThread { public static void main(String[] args) throws InterruptedException {  Semaphore sempA = new Semaphore(1);  Semaphore sempB = new Semaphore(0);  Semaphore sempC = new Semapho

  • JAVA 多线程之信号量(Semaphore)实例详解

    java Semaphore 简介 信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施, 它负责协调各个线程, 以保证它们能够正确.合理的使用公共资源. 一个计数信号量.从概念上讲,信号量维护了一个许可集.如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可.每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者.但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动.拿到信号量的线程可以进入

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

    Java并发编程之Semaphore(信号量)详解及实例 概述 通常情况下,可能有多个线程同时访问数目很少的资源,如客户端建立了若干个线程同时访问同一数据库,这势必会造成服务端资源被耗尽的地步,那么怎样能够有效的来控制不可预知的接入量呢?及在同一时刻只能获得指定数目的数据库连接,在JDK1.5 java.util.concurrent 包中引入了Semaphore(信号量),信号量是在简单上锁的基础上实现的,相当于能令线程安全执行,并初始化为可用资源个数的计数器,通常用于限制可以访问某些资源(物

  • Java并发编程Semaphore计数信号量详解

    Semaphore 是一个计数信号量,它的本质是一个共享锁.信号量维护了一个信号量许可集.线程可以通过调用acquire()来获取信号量的许可:当信号量中有可用的许可时,线程能获取该许可:否则线程必须等待,直到有可用的许可为止. 线程可以通过release()来释放它所持有的信号量许可(用完信号量之后必须释放,不然其他线程可能会无法获取信号量). 简单示例: package me.socketthread; import java.util.concurrent.ExecutorService;

  • 详解java中的互斥锁信号量和多线程等待机制

    互斥锁和信号量都是操作系统中为并发编程设计基本概念,互斥锁和信号量的概念上的不同在于,对于同一个资源,互斥锁只有0和1 的概念,而信号量不止于此.也就是说,信号量可以使资源同时被多个线程访问,而互斥锁同时只能被一个线程访问 互斥锁在java中的实现就是 ReetranLock , 在访问一个同步资源时,它的对象需要通过方法 tryLock() 获得这个锁,如果失败,返回 false,成功返回true.根据返回的信息来判断是否要访问这个被同步的资源.看下面的例子 public class Reen

  • Java编程线程间通信与信号量代码示例

    1.信号量Semaphore 先说说Semaphore,Semaphore可以控制某个资源可被同时访问的个数,通过acquire()获取一个许可,如果没有就等待,而release()释放一个许可.一般用于控制并发线程数,及线程间互斥.另外重入锁ReentrantLock也可以实现该功能,但实现上要复杂些. 功能就类似厕所有5个坑,假如有10个人要上厕所,那么同时只能有多少个人去上厕所呢?同时只能有5个人能够占用,当5个人中的任何一个人让开后,其中等待的另外5个人中又有一个人可以占用了.另外等待的

  • Java编程之多线程死锁与线程间通信简单实现代码

    死锁定义 死锁是指两个或者多个线程被永久阻塞的一种局面,产生的前提是要有两个或两个以上的线程,并且来操作两个或者多个以上的共同资源:我的理解是用两个线程来举例,现有线程A和B同时操作两个共同资源a和b,A操作a的时候上锁LockA,继续执行的时候,A还需要LockB进行下面的操作,这个时候b资源在被B线程操作,刚好被上了锁LockB,假如此时线程B刚好释放了LockB则没有问题,但没有释放LockB锁的时候,线程A和B形成了对LockB锁资源的争夺,从而造成阻塞,形成死锁:具体其死锁代码如下:

  • Java编程利用socket多线程访问服务器文件代码示例

    这篇文章将向大家展示Java编程利用socket多线程访问服务器文件代码示例,如果您想先了解Java多线程socket编程的基础知识,可以看下这篇文章:Java多线程编程实现socket通信示例代码. 接下来进入正文,我们看看利用socket多线程访问服务器代码: ServerMain.java package com.ysk.webServer; import java.io.File; import java.io.IOException; import java.net.ServerSoc

  • Java编程将汉字转Unicode码代码示例

    上一次接触到编码的知识,还是上大学的时候,那时候学的是通信工程专业,有关编码的内容,不记得是在通信原理还是信息论与编码里面学到的了.却依然记得那个信息论与编码的老师,最喜欢吃的是尖椒肥肠盖饭,不知道是尖椒肥肠吃多了还是太聪明的缘故,三十多岁就开始拜顶了.那四年真是一段难忘的回忆... 话不多说,咱们进入正题.这里是一个简单的Java编程将汉字转Unicode码代码示例,下面是代码: package me.socketthread; public class ToUnicode { /** * @

  • Java编程GUI中的事件绑定代码示例

    程序绑定的概念: 绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来.对java来说,绑定分为静态绑定和动态绑定:或者叫做前期绑定和后期绑定 静态绑定: 在程序执行前方法已经被绑定,此时由编译器或其它连接程序实现.例如:C. 针对java简单的可以理解为程序编译期的绑定:这里特别说明一点,java当中的方法只有final,static,private和构造方法是前期绑定 动态绑定 后期绑定:在运行时根据具体对象的类型进行绑定. 若一种语言实现了后期绑定,同时必须提供一些机制,可在运行期间

  • Java编程实现邻接矩阵表示稠密图代码示例

    我们知道,要表示结点,我们可以用一个一维数组来表示,然而对于结点和结点之间的关系,则无法简单地用一维数组来表示了,我们可以用二维数组来表示,也就是一个矩阵形式的表示方法. 我们假设A是这个二维数组,那么A中的一个元素aij不仅体现出了结点vi和结点vj的关系,而且aij的值正可以表示权值的大小. 邻接矩阵模型类 邻接矩阵模型类的类名为AMWGraph.java,能够通过该类构造一个邻接矩阵表示的图,且提供插入结点,插入边,取得某一结点的第一个邻接结点和下一个邻接结点. import java.u

  • Java编程实现五子棋人人对战代码示例

    利用Java,在控制台操作下,编写的五子棋,作为复习二维数组,面向对象等基础知识.w表示白棋,b表示黑棋 import java.util.Scanner; public class MainMethod { public static char[][] c = new char[10][10]; public static void main(String[] args) { MainMethod mainMethod = new MainMethod(); mainMethod.init()

  • Java编程IP地址和数字相互转换代码示例

    最近才知道,将ip地址转换成十进制.八进制.十六进制同样可以访问网站. IP转为数字(第二种算法.用左移.按位或实现.效率更高.): public long ipToLong(String ipAddress) { long result = 0; String[] ipAddressInArray = ipAddress.split("\\."); for (int i = 3; i >= 0; i--) { long ip = Long.parseLong(ipAddress

  • Java编程常见内存溢出异常与代码示例

    Java 堆是用来存储对象实例的, 因此如果我们不断地创建对象, 并且保证 GC Root 和创建的对象之间有可达路径以免对象被垃圾回收, 那么当创建的对象过多时, 会导致 heap 内存不足, 进而引发 OutOfMemoryError 异常. /** * @author xiongyongshun * VM Args: java -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError */ public class OutOfMemoryErrorTe

  • Java编程实现深度优先遍历与连通分量代码示例

    深度优先遍历 深度优先遍历类似于一个人走迷宫: 如图所示,从起点开始选择一条边走到下一个顶点,没到一个顶点便标记此顶点已到达. 当来到一个标记过的顶点时回退到上一个顶点,再选择一条没有到达过的顶点. 当回退到的路口已没有可走的通道时继续回退. 而连通分量,看概念:无向图G的极大连通子图称为G的连通分量( Connected Component).任何连通图的连通分量只有一个,即是其自身,非连通的无向图有多个连通分量. 下面看看具体实例: package com.dataStructure.gra

随机推荐