【胡思乱想】JNI与线程池的维护
JNI中,C/C++代码里创建的资源不由Java GC处理,故这里的资源必须由C/C++代码明确释放。在JNI中,C/C++回调Java的方法是调用一个CallXXMethod函数来实现的,如果回调的方法结束,C/C++执行下一行代码。
故猜测,由C/C++创建的OS线程应该会在运行完run方法后释放,不然好像也没有其他合适的时间点来对线程进行释放了。因为按照语义的话,既然线程的任务已经完成,那线程还留着干什么,就应该被释放。
有些时候,我们需要维护一个线程池来减少创建和释放线程的开销,让一些线程完成当前任务后被收回到线程池,等待接受下一个任务。根据前面的猜测,run方法结束后,OS线程将被释放。我们要维护线程池,就是不能让线程被释放。所以我们就要阻止run方法返回。当Thread.run把target.run执行完的时候,利用wait挂起线程。直到有新的target,才唤醒当前线程。
以下是我在旧版的《Thinking in Enterprise Java》中看到的线程池的实现。
public class Worker extends Thread { //工作者线程
public static final Logger logger = Logger.setLogger("Worker"); //类日志
private String workerId; //工作者ID
private Runnable task; //任务对象
private ThreadPool threadPool; //线程池引用,方便操作。
static { //静态块,配置logger
try {
logger.setUseParentHandlers(false);
FileHandler ferr = new FileHandler("WorkerErr.log");
ferr.setFormatter(new SimpleFormatter());
logger.addHandler(ferr);
} catch(IOException e) {
System.out.println("Logger not initialized.");
}
}
public Worker(String id, ThreadPool pool) {
workerId = id;
threadPool = pool;
start(); //创建即启动
}
public void setTask(Runnable t) { //这里放入新任务,并唤醒线程,进入就绪队列。
task = t;
synchronized(this) {
notify(); //wait、notify方法都必须获取对应的锁
}
}
public void run() {
try {
while(!threadPool.isStopped()) { //如果线程池未停止工作,此线程不释放
synchronized(this) {
if(task != null) {
try {
task.run(); //执行任务
} catch(Exception e) {
logger.log(Level.SERVER, "Exception in source Runnable task", e);
}
threadPool.putWorker(this); //完成当前任务,回收到线程池
}
wait(); //完成任务或无任务时,挂起线程。免得空循环浪费时间片。
}
}
//跳出循环,意味着线程池结束工作,此线程也将停止工作
System.out.println(this + " Stopped");
} catch(InterruptedException e) {
throw new RuntimeException(e);
}
}
public String toString() {
return "Worker: " + workerId;
}
}
public class ThreadPool extends Thread { //线程池, 同样是一个线程,负责接收和分配任务
private static final int DEFAULT_NUM_WORKERS = ; //默认线程池大小为5
private LinkedList workerPool = new LinkedList(); //空闲线程列表
private LinkedList taskQueue = new LinkedList(); //任务列表
private boolean stopped = false; //线程池的工作状态
public ThreadPool() { //默认构造方法,线程池大小默认
this(DEFAULT_NUM_WORKERS);
}
public ThreadPool(int numOfWorkers) { //自定义线程池大小
for(int i=;i<numOfWorkers;i++){
workerPool.add(new Worker("" + i, this));
}
start(); //创建即启动
}
public void run() { //分发任务
try {
while(!stopped) {
if(taskQueue.isEmpty()) { //如果任务队列为空,挂起当前线程。 也就是暂停线程池的分发任务的工作
synchronized(taskQueue) {
taskQueue.wait(); //不管调用哪个对象的wait方法,都是挂起当前执行它的线程。
}
} else if(workerPool.isEmpty()) { //如果没有空闲的线程,则暂停线程池的工作。
synchronized(workerPool) {
workerPool.wait();
}
}
//有任务,且有空闲线程的情况 => 从空闲线程中取出一个线程,让其负责任务队列中的一个任务
getWorker().setTask((Runnable)taskQueue.removeLast());
}
} catch(InterruptedException e) {
throw new RuntimeException(e);
}
}
public void addTask(Runnable task) {
synchronized(taskQueue) {
taskQueue.addFirst(task);
taskQueue.notify(); //通知已有新任务,如果前面线程因无任务被挂起,这个操作将唤醒线程
}
}
public void putWorker(Worker worker) {
synchronized(workerPool) {
workerPool.addFirst(worker);
workerPool.notify(); //通知已有新空闲线程,如果前面线程因无空闲工作者线程被挂起,此操作将唤醒线程
}
}
public Worker getWorker() {
return (Worker) workerPool.removeLast(); //取出一个空闲线程,并从列表中移除。
}
public boolean isStopped() {
return stopped;
}
public void stopThreads() { //关闭线程池
stopped = true;
Iterator it = workerPool.Iterator();
//这里唤醒挂起的工作者线程,使得它醒来并发现ThreadPool已关闭,并结束run方法 => 释放OS线程
while(it.hasNext()) {
Worker w = (Worker)it.next();
synchronized(w) {
w.notify();
}
}
}
}
对这个代码的认识,在注释里已经表现的很清楚了。另外,我还觉得,ThreadPool和Woker的关系有点观察者模式的味道,Woker是观察者,ThreadPool是被观察者/主题。不过,与标准的观察者模式不同的是,ThreadPool接受到新任务(发生了变化),并没有通知所有Worker。
【胡思乱想】JNI与线程池的维护的更多相关文章
- 分享一个自制的 .net线程池
扯淡 由于项目需求,需要开发一些程序去爬取一些网站的信息,算是小爬虫程序吧.爬网页这东西是要经过网络传输,如果程序运行起来串行执行请求爬取,会很慢,我想没人会这样做.为了提高爬取效率,必须使用多线程并 ...
- CompletionService/ExecutorCompletionService/线程池/concurrent包
线程池 线程池的基本思想:线程频繁的创建.销毁会极大地占用系统资源,为了减少系统在创建销毁线程时的开销,线程池应运而生.线程池包括多个已创建的线程,当有任务要在新线程中执行时,将任务提交给线程池,线程 ...
- JAVA基础知识之多线程——线程池
线程池概念 操作系统或者JVM创建一个线程以及销毁一个线程都需要消耗CPU资源,如果创建或者销毁线程的消耗源远远小于执行一个线程的消耗,则可以忽略不计,但是基本相等或者大于执行线程的消耗,而且需要创建 ...
- Linux平台下线程池的原理及实现
转自:http://blog.csdn.net/lmh12506/article/details/7753952 前段时间在github上开了个库,准备实现自己的线程池的,因为换工作的事,一直也没有实 ...
- 【温故而知新-万花筒】C# 异步编程 逆变 协变 委托 事件 事件参数 迭代 线程、多线程、线程池、后台线程
额基本脱离了2.0 3.5的时代了.在.net 4.0+ 时代.一切都是辣么简单! 参考文档: http://www.cnblogs.com/linzheng/archive/2012/04/11/2 ...
- .Net多线程编程—Parallel LINQ、线程池
Parallel LINQ 1 System.Linq.ParallelEnumerable 重要方法概览: 1)public static ParallelQuery<TSource> ...
- Java多线程之Executor框架和手写简易的线程池
目录 Java多线程之一线程及其基本使用 Java多线程之二(Synchronized) Java多线程之三volatile与等待通知机制示例 线程池 什么是线程池 线程池一种线程使用模式,线程池会维 ...
- C#并行编程(2):.NET线程池
线程 Thread 在总结线程池之前,先来看一下.NET线程. .NET线程与操作系统(Windows)线程有什么区别? .NET利用Windows的线程处理功能.在C#程序编写中,我们首先会新建一个 ...
- Java编程的逻辑 (78) - 线程池
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
随机推荐
- kepware http接口 java语言开发
读取某变量的值(OK HTTP OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .u ...
- IntelliJ IDEA配置Tomcat(完整版教程)
查找该问题的童鞋我相信IntelliJ IDEA,Tomcat的下载,JDK等其他的配置都应该完成了,那我直接进入正题了. 1.新建一个项目 2.由于这里我们仅仅为了展示如何成功部署Tomcat,以及 ...
- C语言中:static与extern对变量和函数的作用
1.两者对全局变量 static对全局变量,表示定义一个内部变量 extern对全局变量,表示声明一个外部变量 说明: 1.内部变量:定义的变量只能在本文件中访问,不能被其他文件访问. 2.不同文件中 ...
- codeforces 877b
B. Nikita and string time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- java并发的处理方式
1 什么是并发问题. 多个进程或线程同时(或着说在同一段时间内)访问同一资源会产生并发问题. 银行两操作员同时操作同一账户就是典型的例子.比如A.B操作员同时读取一余额为1000元的账户,A操作员为该 ...
- MySQL5.7Gtid主从复制总是遇到日志被清等出现无法正常主从复制
最近最是在MySQL5.7上的的gtid主从复制问题总是遇上下面问题: Last_Error: Coordinator stopped because there were error(s) in t ...
- Linux下替代grep高效文本搜索工具
1.ack yum install ack 2.ag git clone https://github.com/ggreer/the_silver_searcher.git yum install a ...
- 单片机编译器Keil提供的sprintf有点问题
AduC70xx系列,Keil提供的sprintf函数不太好用,好像有时会引起内存泄漏,造成不可预知的死机情况出现.
- ASP.NET MVC5 高级编程-学习日记-第一章 入门
1.1 ASP.NET MVC 简介 ASP.NET是一种构建Web应用程序的框架,它将一般的MVC(Model-View-Controller)模式应用于ASP.NET框架. 1.1.1 MVC模式 ...
- 解决C#项目出现“此项目引用这台计算机上缺少的 NuGet 程序包。使用 NuGet 程序包还原可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 ..\packages\Microsoft.Net.Compilers.1.0.0\build\Microsoft.Net.Compilers.props”
1.打开项目的.csproj文件 2.删掉如下选中的内容: 3.右键项目-->管理NuGet程序包(N) 找到Microsoft.CodeDom.Providers.DotNetCompiler ...