一说到Java线程同步,首先想到的就是synchronized关键字,用来锁对象。实际上在Java的java.util.concurrent包中就给我们提供了很多关于同步的工具类。这里为大家介绍Semaphore这个类。这个类是干嘛用的呢?就好比信号标识,它把这十个房间的信息都标识到一个电子信息站牌中,这个信息牌管理所有的房间信息,当有空余的房间时,所有需要放物品的线程都会知道,并抢房间的授权资格,当放抢到授权资格的线程放入物品后,所有需取物品的线程就进入放入物品和抢授权资格的过程。具体代码如下,这个例子,实现了多个线程同时往一个容器中放物品,如果这个容器中的物品数大于10的时候,所有放入线程处于等待状态;还实现了多个线程同时往容器中取物品,当容器中物品为空时,取物线程等待。简单一句话描述:在不冲突的过程中从容器中多放,多取。
package thread.semaphore.two;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class SemaphoreTest {
public static void main(String[] args) {
// 线程执行器
ExecutorService executor = Executors.newCachedThreadPool();
// 产生仓库
Warehouse warehouse = new Warehouse();
// 设置限额信号
Semaphore notFull = new Semaphore(10);
// 设置非空信号
Semaphore notEmpty = new Semaphore(0);
// 产生生产者
PutterRunnable putter1 = new PutterRunnable(warehouse, "put1", notFull, notEmpty);
PutterRunnable putter2 = new PutterRunnable(warehouse, "put2", notFull, notEmpty);
// 产生消费者
GetterRunnable getter1 = new GetterRunnable(warehouse, "get1", notFull, notEmpty);
GetterRunnable getter2 = new GetterRunnable(warehouse, "get2", notFull, notEmpty);
executor.execute(putter1);
executor.execute(putter2);
executor.execute(getter1);
// 如果有需要,可以把这个方法放开,就可以实现多放多取。
// executor.execute(getter2);
}
// 数据存储仓库
static class Warehouse {
// 库存容量
List<Object> list = new ArrayList<Object>();
// 核心锁(非冲突锁)
Semaphore core = new Semaphore(1, true);
public void put(Object obj, String threadName) {
try {
// 保证不冲突
core.acquire();
list.add(obj);
// 判断在生产时,填充位的对象是否是已经有值的,如果有则表示程序错误
System.out.println("+++ " + threadName + " list.size = " + list.size() + ";放入的obj=" + obj);
// 退出核心锁
core.release();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
@SuppressWarnings("finally")
public Object get(String threadName) {
Object obj = null;
try {
// 保证不冲突
core.acquire();
obj = list.remove(0);
// 判断在消费时,需要消费位置的对象是否是空的。,如果有则表示程序错误
System.out.println(" --- " + threadName + " list.size = " + list.size() + ";取出的obj=" + obj);
// 退出核心锁
core.release();
} catch (Exception e) {
e.printStackTrace();
} finally {
return obj;
}
}
}
// putter线程,
static class PutterRunnable implements Runnable {
Warehouse warehouse;
Random random;
String rannableName;
// 非满锁
Semaphore notFull;
// 非空锁
Semaphore notEmpty;
public PutterRunnable(Warehouse warehouse, String rannableName, Semaphore notFull, Semaphore notEmpty) {
this.warehouse = warehouse;
random = new Random();
this.rannableName = rannableName;
this.notFull = notFull;
this.notEmpty = notEmpty;
}
@Override
public void run() {
while (true) {
try {
// 获取存储限额的插入许可,如果达到限额,则等待插入许可,否则继续往下执行
notFull.acquire();
warehouse.put((Object) (random.nextInt() + ""), rannableName);
// 插入成功后,则添加非空的授权许可。以供获取线程获取
notEmpty.release();
// TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
static class GetterRunnable implements Runnable {
Warehouse warehouse;
String rannableName;
// 非空锁,当是0的时候进行阻塞
Semaphore notEmpty;
// 非满锁
Semaphore notFull;
public GetterRunnable(Warehouse warehouse, String rannableName, Semaphore notFull, Semaphore notEmpty) {
this.warehouse = warehouse;
this.rannableName = rannableName;
this.notFull = notFull;
this.notEmpty = notEmpty;
}
@Override
public void run() {
while (true) {
try {
// 获取非空授权许可,如果为空,则一直阻塞,等待插入线程插入后添加非空许可
notEmpty.acquire();
warehouse.get(rannableName);
// 添加存储限额的插入许可,表示插入线程可以进行添加操作了
notFull.release();
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
执行结果如下:
<div>
+++ put1 list.size = 1;放入的obj=-2139723420
+++ put2 list.size = 2;放入的obj=-1572405971
+++ put1 list.size = 3;放入的obj=-1705274050
--- get1 list.size = 2;取出的obj=-2139723420
+++ put2 list.size = 3;放入的obj=734422456
+++ put1 list.size = 4;放入的obj=-1619127788
+++ put2 list.size = 5;放入的obj=-1719033923
+++ put1 list.size = 6;放入的obj=-122350698
+++ put2 list.size = 7;放入的obj=2035853367
+++ put1 list.size = 8;放入的obj=-538022868
+++ put2 list.size = 9;放入的obj=-1842381319
+++ put1 list.size = 10;放入的obj=-1810284972
--- get1 list.size = 9;取出的obj=-1572405971
+++ put2 list.size = 10;放入的obj=-555471275
--- get1 list.size = 9;取出的obj=-1705274050
+++ put1 list.size = 10;放入的obj=-1173490502
--- get1 list.size = 9;取出的obj=734422456
+++ put2 list.size = 10;放入的obj=-313790792
--- get1 list.size = 9;取出的obj=-1619127788
+++ put1 list.size = 10;放入的obj=-1067498081
--- get1 list.size = 9;取出的obj=-1719033923
+++ put2 list.size = 10;放入的obj=-1634780208
--- get1 list.size = 9;取出的obj=-122350698
+++ put1 list.size = 10;放入的obj=-1420550696
--- get1 list.size = 9;取出的obj=2035853367
+++ put2 list.size = 10;放入的obj=2036388541
--- get1 list.size = 9;取出的obj=-538022868
+++ put1 list.size = 10;放入的obj=-320507030
--- get1 list.size = 9;取出的obj=-1842381319
+++ put2 list.size = 10;放入的obj=1682783427
--- get1 list.size = 9;取出的obj=-1810284972
+++ put1 list.size = 10;放入的obj=243200254
<div>