首页 > 编程 > Java > 正文

【Java并发编程】01.Semaphore的使用

2019-11-08 02:37:01
字体:
来源:转载
供稿:网友

今天开始准备学习java并发编程。准备把这个系列写到一个专栏里面,记录一下我学习Java并发编程的过程。希望和大家共同进步。

所有代码我会上传到GitHub上面,地址是:https://github.com/mrbcy/JavaConcurrentLearn

这个系列目前更新的部分是《Java并发编程核心方法与框架》的读书笔记。

Semaphore 的同步性

类Semaphore所提供的功能完全就是synchronized关键字的升级版,但它提供的功能更加的强大和方便,主要的作用是控制线程并发的数量。这一点单纯用synchronized是做不到的。

Semaphore发放许可的计算方式是“减法”操作。

public class Service { PRivate Semaphore semaphore = new Semaphore(1); public void testMethod(){ try { semaphore.acquire(); System.out.println(Thread.currentThread().getName() + " begin timer=" + System.currentTimeMillis()); Thread.sleep(5000); System.out.println(Thread.currentThread().getName() + " begin timer=" + System.currentTimeMillis()); semaphore.release(); } catch (Exception e) { e.printStackTrace(); } }}

Semaphore构造方法中的permit是许可的意思,代表同一时间内最多允许多少个线程同时执行acquire和release之间的代码。

acquire()方法代表使用一个许可,做减法操作。

下面我们同时启动几个线程,看一下Semaphore类是否能够控制住并发的数量。

TestThread.java

public class TestThread extends Thread{ private Service service; public TestThread(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.testMethod(); }}

Run.java

package tech.mrbcy.javaconcurrentlearn.e01_1;public class Run { public static void main(String[] args) { Service service = new Service(); TestThread a = new TestThread(service); a.setName("A"); TestThread b = new TestThread(service); b.setName("B"); TestThread c = new TestThread(service); c.setName("C"); a.start(); b.start(); c.start(); }}

输出的结果为:

A begin timer=1487347454779A begin timer=1487347459780B begin timer=1487347459780B begin timer=1487347464781C begin timer=1487347464781C begin timer=1487347469781

可以看出只有一个线程同时执行。

如果把Service类中Semaphore的permit数量改成2,则会有下面的输出结果:

B begin timer=1487347739934A begin timer=1487347739934B end timer=1487347744934A end timer=1487347744934C begin timer=1487347744934C end timer=1487347749935

permits值如果>1,不能保证线程安全,可能出现数据脏读。

动态添加permits

不只可以调用acquire方法和release来使用/释放1个许可,它们可以传入参数,一次性使用或释放多个许可。下面的代码动态的添加了多个permits:

package tech.mrbcy.javaconcurrentlearn.e01_2;import java.util.concurrent.Semaphore;public class Run { public static void main(String[] args) { try { Semaphore semaphore = new Semaphore(5); semaphore.acquire(); semaphore.acquire(); semaphore.acquire(); semaphore.acquire(); semaphore.acquire(); System.out.println(semaphore.availablePermits()); semaphore.release(); semaphore.release(); semaphore.release(); semaphore.release(); semaphore.release(); semaphore.release(); System.out.println(semaphore.availablePermits()); semaphore.release(4); System.out.println(semaphore.availablePermits()); } catch (Exception e) { e.printStackTrace(); } }}

输出的结果是:

0610

获取目前等待线程数

Service.java

package tech.mrbcy.javaconcurrentlearn.e01_3;import java.util.concurrent.Semaphore;public class Service { private Semaphore semaphore = new Semaphore(1); public void testMethod(){ try { semaphore.acquire(); Thread.sleep(1000); System.out.println("大约还有 " + semaphore.getQueueLength() + " 个线程在等待"); System.out.println("是否有线程在等待信号量?" + semaphore.hasQueuedThreads()); } catch (Exception e) { e.printStackTrace(); } finally{ semaphore.release(); } }}

TestThread.java

package tech.mrbcy.javaconcurrentlearn.e01_3;public class TestThread extends Thread{ private Service service; public TestThread(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.testMethod(); }}

Run.java

package tech.mrbcy.javaconcurrentlearn.e01_3;public class Run { public static void main(String[] args) { Service service = new Service(); TestThread firstThread = new TestThread(service); firstThread.start(); TestThread[] threads = new TestThread[4]; for(int i = 0; i < 4; i++){ threads[i] = new TestThread(service); threads[i].start(); } }}

输出结果为:

大约还有 4 个线程在等待是否有线程在等待信号量?true大约还有 3 个线程在等待是否有线程在等待信号量?true大约还有 2 个线程在等待是否有线程在等待信号量?true大约还有 1 个线程在等待是否有线程在等待信号量?true大约还有 0 个线程在等待是否有线程在等待信号量?false

公平信号量与非公平信号量

公平信号量是指先启动的线程一定会先获得锁。非公平信号量则没有这个限制。下面用代码来进行一下实验。

Service.java

package tech.mrbcy.javaconcurrentlearn.e01_4;import java.util.concurrent.Semaphore;public class Service { private boolean isFair = false; private Semaphore semaphore = new Semaphore(1, isFair); public void testMethod(){ try { semaphore.acquire(); System.out.println("ThreadName=" + Thread.currentThread().getName()); } catch (Exception e) { e.printStackTrace(); } finally{ semaphore.release(); } }}

TestThread.java

package tech.mrbcy.javaconcurrentlearn.e01_4;public class TestThread extends Thread{ private Service service; public TestThread(Service service) { super(); this.service = service; } @Override public void run() { super.run(); System.out.println("ThreadName="+this.getName()+" 启动了!"); service.testMethod(); }}

Run.java

package tech.mrbcy.javaconcurrentlearn.e01_4;public class Run { public static void main(String[] args) { Service service = new Service(); TestThread firstThread = new TestThread(service); firstThread.start(); TestThread[] threads = new TestThread[4]; for(int i = 0; i < 4; i++){ threads[i] = new TestThread(service); threads[i].start(); } }}

运行结果:

ThreadName=Thread-1 启动了!ThreadName=Thread-4 启动了!ThreadName=Thread-0 启动了!ThreadName=Thread-4ThreadName=Thread-2 启动了!ThreadName=Thread-2ThreadName=Thread-0ThreadName=Thread-3 启动了!ThreadName=Thread-3ThreadName=Thread-1

如果把Service的isFair改为true,则输出的结果变成:

ThreadName=Thread-2 启动了!ThreadName=Thread-2ThreadName=Thread-3 启动了!ThreadName=Thread-3ThreadName=Thread-0 启动了!ThreadName=Thread-4 启动了!ThreadName=Thread-1 启动了!ThreadName=Thread-0ThreadName=Thread-4ThreadName=Thread-1

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

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

Service.java

package tech.mrbcy.javaconcurrentlearn.e01_5;import java.util.concurrent.Semaphore;public class Service { private Semaphore semaphore = new Semaphore(3); public void testMethod(){ try { semaphore.acquire(); System.out.println("ThreadName=" + Thread.currentThread().getName() + " 准备"); System.out.println("begin hello " + System.currentTimeMillis()); for(int i = 0; i < 5; i++){ System.out.println("ThreadName=" + Thread.currentThread().getName() + " 打印" + (i+1)); } System.out.println("end hello " + System.currentTimeMillis()); semaphore.release(); System.out.println("ThreadName=" + Thread.currentThread().getName() + " 结束"); } catch (Exception e) { e.printStackTrace(); } finally{ } }}

TestThread.java

package tech.mrbcy.javaconcurrentlearn.e01_5;public class TestThread extends Thread{ private Service service; public TestThread(Service service) { super(); this.service = service; } @Override public void run() { super.run(); service.testMethod(); }}

Run.java

package tech.mrbcy.javaconcurrentlearn.e01_5;public class Run { public static void main(String[] args) { Service service = new Service(); TestThread[] threads = new TestThread[12]; for(int i = 0; i < threads.length; i++){ threads[i] = new TestThread(service); threads[i].start(); } }}

运行结果如下:

ThreadName=Thread-2 准备ThreadName=Thread-1 准备ThreadName=Thread-0 准备begin hello 1487433434952begin hello 1487433434952ThreadName=Thread-1 打印1begin hello 1487433434952ThreadName=Thread-1 打印2ThreadName=Thread-2 打印1ThreadName=Thread-1 打印3ThreadName=Thread-0 打印1ThreadName=Thread-1 打印4ThreadName=Thread-1 打印5end hello 1487433434953ThreadName=Thread-2 打印2ThreadName=Thread-3 准备begin hello 1487433434953ThreadName=Thread-3 打印1ThreadName=Thread-1 结束ThreadName=Thread-0 打印2ThreadName=Thread-3 打印2ThreadName=Thread-2 打印3ThreadName=Thread-3 打印3ThreadName=Thread-3 打印4ThreadName=Thread-0 打印3ThreadName=Thread-3 打印5ThreadName=Thread-2 打印4end hello 1487433434955ThreadName=Thread-0 打印4ThreadName=Thread-3 结束ThreadName=Thread-2 打印5ThreadName=Thread-0 打印5ThreadName=Thread-4 准备end hello 1487433434955ThreadName=Thread-0 结束end hello 1487433434955ThreadName=Thread-6 准备ThreadName=Thread-7 准备begin hello 1487433434956ThreadName=Thread-7 打印1ThreadName=Thread-7 打印2begin hello 1487433434955ThreadName=Thread-7 打印3begin hello 1487433434956ThreadName=Thread-6 打印1ThreadName=Thread-6 打印2ThreadName=Thread-6 打印3ThreadName=Thread-6 打印4ThreadName=Thread-2 结束ThreadName=Thread-6 打印5ThreadName=Thread-7 打印4ThreadName=Thread-7 打印5ThreadName=Thread-4 打印1end hello 1487433434956end hello 1487433434956ThreadName=Thread-7 结束ThreadName=Thread-4 打印2ThreadName=Thread-8 准备ThreadName=Thread-6 结束begin hello 1487433434956ThreadName=Thread-5 准备begin hello 1487433434957ThreadName=Thread-5 打印1ThreadName=Thread-4 打印3ThreadName=Thread-5 打印2ThreadName=Thread-5 打印3ThreadName=Thread-5 打印4ThreadName=Thread-5 打印5end hello 1487433434957ThreadName=Thread-5 结束ThreadName=Thread-8 打印1ThreadName=Thread-9 准备begin hello 1487433434957ThreadName=Thread-4 打印4ThreadName=Thread-9 打印1ThreadName=Thread-9 打印2ThreadName=Thread-9 打印3ThreadName=Thread-8 打印2ThreadName=Thread-8 打印3ThreadName=Thread-9 打印4ThreadName=Thread-4 打印5ThreadName=Thread-9 打印5ThreadName=Thread-8 打印4ThreadName=Thread-8 打印5end hello 1487433434957end hello 1487433434957ThreadName=Thread-10 准备begin hello 1487433434957ThreadName=Thread-10 打印1ThreadName=Thread-10 打印2ThreadName=Thread-9 结束end hello 1487433434957ThreadName=Thread-10 打印3ThreadName=Thread-4 结束ThreadName=Thread-11 准备ThreadName=Thread-10 打印4ThreadName=Thread-8 结束ThreadName=Thread-10 打印5end hello 1487433434959begin hello 1487433434959ThreadName=Thread-10 结束ThreadName=Thread-11 打印1ThreadName=Thread-11 打印2ThreadName=Thread-11 打印3ThreadName=Thread-11 打印4ThreadName=Thread-11 打印5end hello 1487433434960ThreadName=Thread-11 结束

可以看出有多个线程在同时运行。

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

这个实验是在上面的多进路-多处理-多出路实验基础上稍加修改的。目标是允许多个线程同时处理任务,但执行任务的顺序缺是同步的,也就是阻塞的,所以称为单处理。

Service.java

package tech.mrbcy.javaconcurrentlearn.e01_6;import java.util.concurrent.Semaphore;import java.util.concurrent.locks.ReentrantLock;public class Service { private Semaphore semaphore = new Semaphore(3); private ReentrantLock lock = new ReentrantLock(); public void testMethod(){ try { semaphore.acquire(); System.out.println("ThreadName=" + Thread.currentThread().getName() + " 准备"); lock.lock(); System.out.println("begin hello " + System.currentTimeMillis()); for(int i = 0; i < 5; i++){ System.out.println("ThreadName=" + Thread.currentThread().getName() + " 打印" + (i+1)); } System.out.println("end hello " + System.currentTimeMillis()); lock.unlock(); semaphore.release(); System.out.println("ThreadName=" + Thread.currentThread().getName() + " 结束"); } catch (Exception e) { e.printStackTrace(); } finally{ } }}

其他都没有变化。

输出结果如下:

ThreadName=Thread-1 准备ThreadName=Thread-0 准备ThreadName=Thread-2 准备begin hello 1487433927769ThreadName=Thread-1 打印1ThreadName=Thread-1 打印2ThreadName=Thread-1 打印3ThreadName=Thread-1 打印4ThreadName=Thread-1 打印5end hello 1487433927769ThreadName=Thread-11 准备begin hello 1487433927769ThreadName=Thread-1 结束ThreadName=Thread-0 打印1ThreadName=Thread-0 打印2ThreadName=Thread-0 打印3ThreadName=Thread-0 打印4ThreadName=Thread-0 打印5end hello 1487433927770ThreadName=Thread-0 结束ThreadName=Thread-3 准备begin hello 1487433927770ThreadName=Thread-2 打印1ThreadName=Thread-2 打印2ThreadName=Thread-2 打印3ThreadName=Thread-2 打印4ThreadName=Thread-2 打印5end hello 1487433927771ThreadName=Thread-2 结束ThreadName=Thread-4 准备begin hello 1487433927771ThreadName=Thread-11 打印1ThreadName=Thread-11 打印2ThreadName=Thread-11 打印3ThreadName=Thread-11 打印4ThreadName=Thread-11 打印5end hello 1487433927771ThreadName=Thread-11 结束ThreadName=Thread-5 准备begin hello 1487433927771ThreadName=Thread-3 打印1ThreadName=Thread-3 打印2ThreadName=Thread-3 打印3ThreadName=Thread-3 打印4ThreadName=Thread-3 打印5end hello 1487433927772ThreadName=Thread-3 结束ThreadName=Thread-6 准备begin hello 1487433927772ThreadName=Thread-4 打印1ThreadName=Thread-4 打印2ThreadName=Thread-4 打印3ThreadName=Thread-4 打印4ThreadName=Thread-4 打印5end hello 1487433927772ThreadName=Thread-4 结束begin hello 1487433927772ThreadName=Thread-7 准备ThreadName=Thread-5 打印1ThreadName=Thread-5 打印2ThreadName=Thread-5 打印3ThreadName=Thread-5 打印4ThreadName=Thread-5 打印5end hello 1487433927772ThreadName=Thread-5 结束begin hello 1487433927772ThreadName=Thread-9 准备ThreadName=Thread-6 打印1ThreadName=Thread-6 打印2ThreadName=Thread-6 打印3ThreadName=Thread-6 打印4ThreadName=Thread-6 打印5end hello 1487433927772ThreadName=Thread-6 结束ThreadName=Thread-8 准备begin hello 1487433927773ThreadName=Thread-7 打印1ThreadName=Thread-7 打印2ThreadName=Thread-7 打印3ThreadName=Thread-7 打印4ThreadName=Thread-7 打印5end hello 1487433927773ThreadName=Thread-7 结束ThreadName=Thread-10 准备begin hello 1487433927773ThreadName=Thread-9 打印1ThreadName=Thread-9 打印2ThreadName=Thread-9 打印3ThreadName=Thread-9 打印4ThreadName=Thread-9 打印5end hello 1487433927773ThreadName=Thread-9 结束begin hello 1487433927773ThreadName=Thread-8 打印1ThreadName=Thread-8 打印2ThreadName=Thread-8 打印3ThreadName=Thread-8 打印4ThreadName=Thread-8 打印5end hello 1487433927773ThreadName=Thread-8 结束begin hello 1487433927773ThreadName=Thread-10 打印1ThreadName=Thread-10 打印2ThreadName=Thread-10 打印3ThreadName=Thread-10 打印4ThreadName=Thread-10 打印5end hello 1487433927773ThreadName=Thread-10 结束

使用Semaphore创建字符串池

这个demo涉及到了一个新的概念:Condition。详细的说明可以参考http://ifeve.com/understand-condition/

ListPool.java

package tech.mrbcy.javaconcurrentlearn.e01_7;import java.util.ArrayList;import java.util.List;import java.util.concurrent.Semaphore;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;/** * Condition 可以参考http://ifeve.com/understand-condition/ * @author mrbcy * */public class ListPool { private int poolMaxSize = 3; private int semaphorePermits = 5; private List<String> list = new ArrayList<String>(); private Semaphore concurrencySemaphore = new Semaphore(semaphorePermits); private ReentrantLock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public ListPool(){ for (int i=0; i < poolMaxSize; i++){ list.add(" mrbcy " + (i + 1)); } } public String get(){ String getString = null; try { concurrencySemaphore.acquire(); lock.lock(); while(list.size() == 0){ condition.await(); } getString = list.remove(0); lock.unlock(); } catch (Exception e) { e.printStackTrace(); } return getString; } public void put(String stringValue){ lock.lock(); list.add(stringValue); condition.signalAll(); lock.unlock(); concurrencySemaphore.release(); }}

MyThread.java

package tech.mrbcy.javaconcurrentlearn.e01_7;public class MyThread extends Thread{ private ListPool listPool; public MyThread(ListPool listPool) { super(); this.listPool = listPool; } @Override public void run() { super.run(); for(int i = 0; i < Integer.MAX_VALUE; i++){ String getString = listPool.get(); System.out.println(Thread.currentThread().getName() + " 取得值 " + getString); listPool.put(getString); } }}

Run.java

package tech.mrbcy.javaconcurrentlearn.e01_7;public class Run { public static void main(String[] args) { ListPool listPool = new ListPool(); MyThread[] threads = new MyThread[12]; for(int i = 0; i < threads.length; i++){ threads[i] = new MyThread(listPool); threads[i].start(); } }}

运行结果:

Thread-9 取得值 mrbcy 2Thread-9 取得值 mrbcy 2Thread-9 取得值 mrbcy 2Thread-9 取得值 mrbcy 2Thread-9 取得值 mrbcy 2Thread-9 取得值 mrbcy 2Thread-10 取得值 mrbcy 2Thread-3 取得值 mrbcy 3Thread-10 取得值 mrbcy 2Thread-10 取得值 mrbcy 2Thread-10 取得值 mrbcy 2Thread-10 取得值 mrbcy 2Thread-10 取得值 mrbcy 2Thread-7 取得值 mrbcy 2Thread-4 取得值 mrbcy 1Thread-4 取得值 mrbcy 1Thread-4 取得值 mrbcy 1Thread-4 取得值 mrbcy 1Thread-4 取得值 mrbcy 1Thread-9 取得值 mrbcy 1Thread-9 取得值 mrbcy 1Thread-4 取得值 mrbcy 1Thread-4 取得值 mrbcy 1Thread-10 取得值 mrbcy 1Thread-10 取得值 mrbcy 1Thread-9 取得值 mrbcy 1Thread-7 取得值 mrbcy 2Thread-4 取得值 mrbcy 2Thread-3 取得值 mrbcy 3Thread-10 取得值 mrbcy 3Thread-4 取得值 mrbcy 2Thread-7 取得值 mrbcy 2Thread-7 取得值 mrbcy 2Thread-3 取得值 mrbcy 2Thread-3 取得值 mrbcy 2Thread-4 取得值 mrbcy 2Thread-9 取得值 mrbcy 1Thread-9 取得值 mrbcy 1Thread-4 取得值 mrbcy 2Thread-10 取得值 mrbcy 3Thread-4 取得值 mrbcy 2

Semaphore多生产者多消费者实验

本实验的目的不光是实现生产者与消费者模式,还要限制生产者与消费者的数量。

RepastService.java

package tech.mrbcy.javaconcurrentlearn.e01_8;import java.util.concurrent.Semaphore;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;public class RepastService { volatile private Semaphore setSemaphore = new Semaphore(10); // 生产者 volatile private Semaphore getSemaphore = new Semaphore(20); // 消费者 volatile private ReentrantLock lock = new ReentrantLock(); volatile private Condition setCondition = lock.newCondition(); volatile private Condition getCondition = lock.newCondition(); // 暂存产品,只能有4个 volatile private Object[] produceShelf = new Object[4]; private boolean isEmpty() { boolean isEmpty = true; for(int i = 0; i < produceShelf.length; i++){ if(produceShelf[i] != null){ isEmpty = false; break; } } return isEmpty; } private boolean isFull() { boolean isFull = true; for(int i = 0; i < produceShelf.length; i++){ if(produceShelf[i] == null){ isFull = false; break; } } return isFull; } public void set() { try { setSemaphore.acquire(); lock.lock(); while(isFull()){ setCondition.await(); } for(int i = 0; i < produceShelf.length; i++){ if(produceShelf[i] == null){ produceShelf[i] = "数据"; System.out.println(Thread.currentThread().getName() + " 生产了 " + produceShelf[i]); break; } } getCondition.signalAll(); lock.unlock(); } catch (Exception e) { e.printStackTrace(); }finally{ setSemaphore.release(); } } public void get() { try { getSemaphore.acquire(); lock.lock(); while (isEmpty()){ getCondition.await(); } for(int i = 0; i < produceShelf.length; i++){ if(produceShelf[i] != null){ System.out.println(Thread.currentThread().getName() + " 消费了 " + produceShelf[i]); produceShelf[i] = null; break; } } setCondition.signalAll(); lock.unlock(); } catch (Exception e) { e.printStackTrace(); } finally { getSemaphore.release(); } }}

ThreadC.java

package tech.mrbcy.javaconcurrentlearn.e01_8;public class ThreadC extends Thread{ private RepastService service; public ThreadC(RepastService service) { super(); this.service = service; } @Override public void run() { super.run(); service.get(); }}

ThreadP.java

package tech.mrbcy.javaconcurrentlearn.e01_8;public class ThreadP extends Thread{ private RepastService service; public ThreadP(RepastService service) { super(); this.service = service; } @Override public void run() { super.run(); service.set(); }}

Run.java

package tech.mrbcy.javaconcurrentlearn.e01_8;public class Run { public static void main(String[] args) throws InterruptedException { RepastService service = new RepastService(); ThreadP[] threadPs = new ThreadP[60]; ThreadC[] threadCs = new ThreadC[60]; for(int i = 0; i < 60; i++){ threadPs[i] = new ThreadP(service); threadCs[i] = new ThreadC(service); } Thread.sleep(2000); for(int i = 0; i < 60; i++){ threadPs[i].start(); threadCs[i].start(); } }}

运行结果:

Thread-0 生产了 数据Thread-8 生产了 数据Thread-9 消费了 数据Thread-1 消费了 数据Thread-12 生产了 数据Thread-13 消费了 数据Thread-2 生产了 数据Thread-18 生产了 数据Thread-23 消费了 数据Thread-19 消费了 数据Thread-20 生产了 数据Thread-3 消费了 数据Thread-4 生产了 数据Thread-6 生产了 数据Thread-28 生产了 数据Thread-5 消费了 数据Thread-36 生产了 数据Thread-37 消费了 数据Thread-41 消费了 数据Thread-11 消费了 数据Thread-10 生产了 数据Thread-7 消费了 数据Thread-14 生产了 数据Thread-16 生产了 数据Thread-54 生产了 数据Thread-15 消费了 数据Thread-61 消费了 数据Thread-63 消费了 数据Thread-24 生产了 数据Thread-42 生产了 数据Thread-25 消费了 数据Thread-67 消费了 数据Thread-22 生产了 数据Thread-71 消费了 数据Thread-30 生产了 数据Thread-73 消费了 数据Thread-26 生产了 数据Thread-31 消费了 数据Thread-32 生产了 数据Thread-33 消费了 数据Thread-38 生产了 数据Thread-89 消费了 数据Thread-40 生产了 数据Thread-39 消费了 数据Thread-34 生产了 数据Thread-55 消费了 数据Thread-94 生产了 数据Thread-100 生产了 数据Thread-59 消费了 数据Thread-58 生产了 数据Thread-109 消费了 数据Thread-60 生产了 数据Thread-110 生产了 数据Thread-112 生产了 数据Thread-57 消费了 数据Thread-44 生产了 数据Thread-117 消费了 数据Thread-69 消费了 数据Thread-119 消费了 数据Thread-87 消费了 数据Thread-46 生产了 数据Thread-21 消费了 数据Thread-74 生产了 数据Thread-68 生产了 数据Thread-27 消费了 数据Thread-29 消费了 数据Thread-52 生产了 数据Thread-75 消费了 数据Thread-50 生产了 数据Thread-78 生产了 数据Thread-76 生产了 数据Thread-80 生产了 数据Thread-77 消费了 数据Thread-48 生产了 数据Thread-35 消费了 数据Thread-56 生产了 数据Thread-45 消费了 数据Thread-81 消费了 数据Thread-43 消费了 数据Thread-53 消费了 数据Thread-62 生产了 数据Thread-114 生产了 数据Thread-116 生产了 数据Thread-64 生产了 数据Thread-85 消费了 数据Thread-91 消费了 数据Thread-93 消费了 数据Thread-65 消费了 数据Thread-66 生产了 数据Thread-104 生产了 数据Thread-98 生产了 数据Thread-95 消费了 数据Thread-17 消费了 数据Thread-70 生产了 数据Thread-106 生产了 数据Thread-97 消费了 数据Thread-79 消费了 数据Thread-101 消费了 数据Thread-72 生产了 数据Thread-103 消费了 数据Thread-82 生产了 数据Thread-99 消费了 数据Thread-84 生产了 数据Thread-105 消费了 数据Thread-86 生产了 数据Thread-107 消费了 数据Thread-90 生产了 数据Thread-88 生产了 数据Thread-92 生产了 数据Thread-96 生产了 数据Thread-111 消费了 数据Thread-113 消费了 数据Thread-51 消费了 数据Thread-115 消费了 数据Thread-102 生产了 数据Thread-108 生产了 数据Thread-118 生产了 数据Thread-49 消费了 数据Thread-47 消费了 数据Thread-83 消费了 数据

总结

这篇博客主要使用了Semaphore类提供的各种方法,还用字符串池以及生产者消费者的例子进行了综合的应用。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表