java并发编程之Semaphore和Exchanger的使用

1. Semaphore的使用

1.1 Semaphore的使用

此类的主要作用就是限制线程并发的数量,如果不限制线程并发的数量,则CPU的资源很快就被耗尽,每个线程执行的任务是相当缓慢。
Semaphore类发放许可的计算方式是“减去”操作。
1.1.1 Semaphore的同步性

private Semaphore semaphore = new Semaphore(2);

类Semaphore的构造函数参数permits是许可的意思,代表同一时间内,最多允许多少个线程同时执行acquire()和release()之间的代码。

无参方法acquire()的作用是使用一个许可,是减法操作。

1.1.2 Semaphore构造方法permits参数作用

private Semaphore semaphore = new Semaphore(int permits);
表示同一时间内最多有permits个线程执行 acquire()和release()之间的代码。

注意:对Semaphore类的构造方法传递的参数permits值如果大于1时,该类并不能保证线程安全性,因为还是有可能会出现多个线程共同访问实例变量,导致出现脏数据的情况。
1.1.3 方法acquire(int permits)参数作用及动态添加permits许可数量

 private Semaphore semaphore = new Semaphore(10);//10并不是最终的许可数量,
// 仅仅是初始的状态值
 semaphore.acquire(int permits);//获得permits个许可
 semaphore.release(int permits);//释放permits个许可
 

1.1.4 方法acquireUninterruptibly()的使用

方法acquireUninterruptibly()的作用是使等待进入acquire()方法的线程,不允许被中断。

1.1.5 方法availablePermits()和drainPermits()

availablePermits()返回此Semaphore对象中当前可用的许可数。
drainPremits() 获取并返回立即可用的所有许可个数,并且将可用许可置0。

1.1.6 方法getQueueLength()和hasQueuedThreads()

getQueueLength() 获得等待许可的线程个数
hasQueuedThreads()判断有没有线程在等待这个许可

1.1.7 公平与非公平信号量

private Semaphore semaphore = new Semaphore(int permits,boolean fair) fair设置是否为公平信号量,默认为false

1.1.8 方法tryAcquire()的使用

无参方法tryAcquire() 的作用是尝试地获得一个许可,如果获取不到则返回false,此方法通常与if语句结合使用,其具有无阻塞的特点。无阻塞的特点可以使线程不至于在同步处一直持续等待的状态,如果if语句判断不成立则线程会继续走else语句,程序会继续向下执行。
方法tryAcquire(int permits) 尝试地获得x个许可,如果获取不到则返回false
方法tryAcquire(long timeout,TimeUnit unit) 在指定的时间内尝试地获得1个许可,如果获取不到则返回false
方法tryAcquire(int permits,long timeout,TimeUnit unit) 在指定的时间内尝试获取x个许可,如果获取不到返回false

1.1.9 多进路-多处理-多出路实验

本实现的目标是允许多个线程同时处理任务,更具体来讲,也就是每个线程都在处理自己的任务。

public class Service{
private Semaphore semaphore = new Semaphore(3);
 public void say(){
 semaphore.acquire();
 ..................
 semaphore.release();
}
}

1.1.10 多进路-单处理-多出路实验

本实现的目标是允许多个线程同时处理的任务,但执行任务的顺序却是同步的,也就是阻塞的,所以也称单处理。

public class Service{
 private Semaphore semaphore = new Semaphore(3);
 private ReentrantLock lock = new ReentrantLock();
 semaphore.acquire();
 lock.lock();
 ..................
 lock.unlock();
 semaphore.release();
}

1.1.11 使用Semaphore创建字符串池

实验代码

1.1.12 使用Semaphore实现多生产者/多消费者模式

实验代码

类Semaphore提供了限制并发线程数的功能,此功能在默认的synchronized中是不提供的。

2. Exchanger的使用

类Exchanger的功能可以使2个线程之间传输数据,它比生产者/消费者模式使用的wait/notify要更加方便
2.1 方法exchange()阻塞的特性

类Exchanger中的exchange()方法具有阻塞的特色,也就是此方法被调用后等待其他线程来取得数据,如果没有其他线程取得数据,则一直阻塞等待。

package cn.yu.Exchanger;

import java.util.concurrent.Exchanger;

public class ThreadA extends Thread {
   private Exchanger<String> exchanger;
   public ThreadA(Exchanger<String> exchanger) {
	   super();
	   this.exchanger = exchanger;
   }
   public void run() {
	   try {
		System.out.println("在线程A中得到线程B的值:"+exchanger.exchange("我是线程A发送给线程B的值"));
	} catch (InterruptedException e) {
		
		e.printStackTrace();
	}
   }
}

package cn.yu.Exchanger;

import java.util.concurrent.Exchanger;

public class ThreadB extends Thread {
	 private Exchanger<String> exchanger;
	   public ThreadB(Exchanger<String> exchanger) {
		   super();
		   this.exchanger = exchanger;
	   }
	  
	public void run() {
		   try {
			System.out.println("在线程B中得到线程A的值:"+exchanger.exchange("我是线程B发送给线程A的值"));
		} catch (InterruptedException e) {
			
			e.printStackTrace();
		}
	   }
}

package cn.yu.Exchanger;

import java.util.concurrent.Exchanger;

public class Test {

	public static void main(String[] args) {
      Exchanger<String> exchanger = new Exchanger<String>();
      ThreadA a = new ThreadA(exchanger);
      ThreadB b = new ThreadB(exchanger);
      a.start();
      b.start();
      
	}
}

运行结果:

在线程B中得到线程A的值:我是线程A发送给线程B的值
在线程A中得到线程B的值:我是线程B发送给线程A的值

2.2 方法exchange(V v,long timeout,TimeUnit unit)阻塞的特性

当调用exchange(V x,long timeout,TimeUnit unit)方法后在指定的时间内没有其他线程获取数据,则出现超时异常。

本章总结:
类Semaphore的主要作用是限制并发执行的线程个数,它具有synchronized所不具有的强大功能,比如等待获得许可的同时可以加入等待时间,还有尝试是否可以持有锁等这类扩展功能。
Exchanger是线程间传输数据的方式之一,而且在传输的数据类型上并没有任何限制。

你可能感兴趣的:(Java并发编程)