- 浏览: 411947 次
- 性别:
- 来自: 北京
-
文章分类
- 全部博客 (325)
- 神经网络 (1)
- javascript (11)
- 数据结构 (2)
- 计算机图形学 (11)
- 模式识别 (1)
- 前端开发 (14)
- 机器学习 (11)
- ios开发 (50)
- Python (9)
- HTML5 (4)
- 计算机视觉 (9)
- 数字图像处理 (7)
- 架构设计 (19)
- 数据库设计 (9)
- 算法设计 (59)
- Java (37)
- 其他 (3)
- 游戏开发 (5)
- c++ (17)
- Linux (3)
- TCP/IP (2)
- Flex (41)
- 健康 (6)
- AI (2)
- 工具 (1)
- 数据挖掘 (1)
- 性能优化 (6)
- 综合 (2)
- 网络通信 (12)
- Android (2)
- UML (3)
- 软件设计 (11)
- 编程经验 (7)
- J2EE (1)
- 多媒体技术 (3)
- 数学 (7)
- php (4)
- 设计 (1)
- CS (2)
- 计算机理论 (1)
- 信息安全 (1)
最新评论
-
ahead_zhan:
good good good
flex3控件_ModuleLoader -
lonerzf:
好样的。非常感谢楼主
OpenCV视频教程整理 -
lonerzf:
好样的。谢谢~
OpenCV视频教程整理 -
coding1688:
博主说的不错,我在实现瀑布流布局时也用的masonry插件,有 ...
Javascript 瀑布流式布局及其动态效果的实现 -
snowolf:
除非玩游戏,不然没啥win的事情,或者用win的银行客户端,通 ...
macbook安装操作系统的机理分析
建议:在阅读本文前,先理一理同步的知识,特别是syncronized同步关键字的用法。
关于我对同步的认识,要缘于大三年的一本书,书名好像是 Java 实战,这本书写得实在太妙了,真正的从理论到实践,从截图分析到.class字节码分析。哇,我想市场上很难买到这么精致的书了。作为一个Java爱好者,我觉得绝对值得一读。
我对此书印象最深之一的就是:equal()方法,由浅入深,经典!
还有就是同步了,其中提到了我的几个编程误区,以前如何使用同步提高性能等等,通过学习,使我对同步的认识进一步加深。
简单介绍
创建线程有两种方式:继承Thread或实现Runnable。Thread实现了Runnable接口,提供了一个空的run()方法,所以不论是继承Thread还是实现Runnable,都要有自己的run()方法。
一个线程创建后就存在,调用start()方法就开始运行(执行run()方法),调用wait进入等待或调用sleep进入休眠期,顺利运行完毕或休眠被中断或运行过程中出现异常而退出。
wait和sleep比较:
sleep方法有:sleep(long millis),sleep(long millis, long nanos),调用sleep方法后,当前线程进入休眠期,暂停执行,但该线程继续拥有监视资源的所有权。到达休眠时间后线程将继续执行,直到完成。若在休眠期另一线程中断该线程,则该线程退出。
wait方法有:wait(),wait(long timeout),wait(long timeout, long nanos),调用wait方法后,该线程放弃监视资源的所有权进入等待状态;
wait():等待有其它的线程调用notify()或notifyAll()进入调度状态,与其它线程共同争夺监视。wait()相当于wait(0),wait(0, 0)。
wait(long timeout):当其它线程调用notify()或notifyAll(),或时间到达timeout亳秒,或有其它某线程中断该线程,则该线程进入调度状态。
wait(long timeout, long nanos):相当于wait(1000000*timeout + nanos),只不过时间单位为纳秒。
线程池:
多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。
如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
一个线程池包括以下四个基本组成部分:
1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:
假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。
/** 线程池类,工作线程作为其内部类 **/
package org.ymcn.util;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
/**
* 线程池
* 创建线程池,销毁线程池,添加新任务
*
* @author obullxl
*/
public final class ThreadPool {
private static Logger logger = Logger.getLogger(ThreadPool.class);
private static Logger taskLogger = Logger.getLogger("TaskLogger");
private static boolean debug = taskLogger.isDebugEnabled();
// private static boolean debug = taskLogger.isInfoEnabled();
/* 单例 */
private static ThreadPool instance = ThreadPool.getInstance();
public static final int SYSTEM_BUSY_TASK_COUNT = 150;
/* 默认池中线程数 */
public static int worker_num = 5;
/* 已经处理的任务数 */
private static int taskCounter = 0;
public static boolean systemIsBusy = false;
private static List<Task> taskQueue = Collections
.synchronizedList(new LinkedList<Task>());
/* 池中的所有线程 */
public PoolWorker[] workers;
private ThreadPool() {
workers = new PoolWorker[5];
for (int i = 0; i < workers.length; i++) {
workers[i] = new PoolWorker(i);
}
}
private ThreadPool(int pool_worker_num) {
worker_num = pool_worker_num;
workers = new PoolWorker[worker_num];
for (int i = 0; i < workers.length; i++) {
workers[i] = new PoolWorker(i);
}
}
public static synchronized ThreadPool getInstance() {
if (instance == null)
return new ThreadPool();
return instance;
}
/**
* 增加新的任务
* 每增加一个新任务,都要唤醒任务队列
* @param newTask
*/
public void addTask(Task newTask) {
synchronized (taskQueue) {
newTask.setTaskId(++taskCounter);
newTask.setSubmitTime(new Date());
taskQueue.add(newTask);
/* 唤醒队列, 开始执行 */
taskQueue.notifyAll();
}
logger.info("Submit Task<" + newTask.getTaskId() + ">: "
+ newTask.info());
}
/**
* 批量增加新任务
* @param taskes
*/
public void batchAddTask(Task[] taskes) {
if (taskes == null || taskes.length == 0) {
return;
}
synchronized (taskQueue) {
for (int i = 0; i < taskes.length; i++) {
if (taskes[i] == null) {
continue;
}
taskes[i].setTaskId(++taskCounter);
taskes[i].setSubmitTime(new Date());
taskQueue.add(taskes[i]);
}
/* 唤醒队列, 开始执行 */
taskQueue.notifyAll();
}
for (int i = 0; i < taskes.length; i++) {
if (taskes[i] == null) {
continue;
}
logger.info("Submit Task<" + taskes[i].getTaskId() + ">: "
+ taskes[i].info());
}
}
/**
* 线程池信息
* @return
*/
public String getInfo() {
StringBuffer sb = new StringBuffer();
sb.append("\nTask Queue Size:" + taskQueue.size());
for (int i = 0; i < workers.length; i++) {
sb.append("\nWorker " + i + " is "
+ ((workers[i].isWaiting()) ? "Waiting." : "Running."));
}
return sb.toString();
}
/**
* 销毁线程池
*/
public synchronized void destroy() {
for (int i = 0; i < worker_num; i++) {
workers[i].stopWorker();
workers[i] = null;
}
taskQueue.clear();
}
/**
* 池中工作线程
*
* @author obullxl
*/
private class PoolWorker extends Thread {
private int index = -1;
/* 该工作线程是否有效 */
private boolean isRunning = true;
/* 该工作线程是否可以执行新任务 */
private boolean isWaiting = true;
public PoolWorker(int index) {
this.index = index;
start();
}
public void stopWorker() {
this.isRunning = false;
}
public boolean isWaiting() {
return this.isWaiting;
}
/**
* 循环执行任务
* 这也许是线程池的关键所在
*/
public void run() {
while (isRunning) {
Task r = null;
synchronized (taskQueue) {
while (taskQueue.isEmpty()) {
try {
/* 任务队列为空,则等待有新任务加入从而被唤醒 */
taskQueue.wait(20);
} catch (InterruptedException ie) {
logger.error(ie);
}
}
/* 取出任务执行 */
r = (Task) taskQueue.remove(0);
}
if (r != null) {
isWaiting = false;
try {
if (debug) {
r.setBeginExceuteTime(new Date());
taskLogger.debug("Worker<" + index
+ "> start execute Task<" + r.getTaskId() + ">");
if (r.getBeginExceuteTime().getTime()
- r.getSubmitTime().getTime() > 1000)
taskLogger.debug("longer waiting time. "
+ r.info() + ",<" + index + ">,time:"
+ (r.getFinishTime().getTime() - r
.getBeginExceuteTime().getTime()));
}
/* 该任务是否需要立即执行 */
if (r.needExecuteImmediate()) {
new Thread(r).start();
} else {
r.run();
}
if (debug) {
r.setFinishTime(new Date());
taskLogger.debug("Worker<" + index
+ "> finish task<" + r.getTaskId() + ">");
if (r.getFinishTime().getTime()
- r.getBeginExceuteTime().getTime() > 1000)
taskLogger.debug("longer execution time. "
+ r.info() + ",<" + index + ">,time:"
+ (r.getFinishTime().getTime() - r
.getBeginExceuteTime().getTime()));
}
} catch (Exception e) {
e.printStackTrace();
logger.error(e);
}
isWaiting = true;
r = null;
}
}
}
}
}
/** 任务接口类 **/
package org.ymcn.util;
import java.util.Date;
/**
* 所有任务接口
* 其他任务必须继承访类
*
* @author obullxl
*/
public abstract class Task implements Runnable {
// private static Logger logger = Logger.getLogger(Task.class);
/* 产生时间 */
private Date generateTime = null;
/* 提交执行时间 */
private Date submitTime = null;
/* 开始执行时间 */
private Date beginExceuteTime = null;
/* 执行完成时间 */
private Date finishTime = null;
private long taskId;
public Task() {
this.generateTime = new Date();
}
/**
* 任务执行入口
*/
public void run() {
/**
* 相关执行代码
*
* beginTransaction();
*
* 执行过程中可能产生新的任务 subtask = taskCore();
*
* commitTransaction();
*
* 增加新产生的任务 ThreadPool.getInstance().batchAddTask(taskCore());
*/
}
/**
* 所有任务的核心 所以特别的业务逻辑执行之处
*
* @throws Exception
*/
public abstract Task[] taskCore() throws Exception;
/**
* 是否用到数据库
*
* @return
*/
protected abstract boolean useDb();
/**
* 是否需要立即执行
*
* @return
*/
protected abstract boolean needExecuteImmediate();
/**
* 任务信息
*
* @return String
*/
public abstract String info();
public Date getGenerateTime() {
return generateTime;
}
public Date getBeginExceuteTime() {
return beginExceuteTime;
}
public void setBeginExceuteTime(Date beginExceuteTime) {
this.beginExceuteTime = beginExceuteTime;
}
public Date getFinishTime() {
return finishTime;
}
public void setFinishTime(Date finishTime) {
this.finishTime = finishTime;
}
public Date getSubmitTime() {
return submitTime;
}
public void setSubmitTime(Date submitTime) {
this.submitTime = submitTime;
}
public long getTaskId() {
return taskId;
}
public void setTaskId(long taskId) {
this.taskId = taskId;
}
}
关于我对同步的认识,要缘于大三年的一本书,书名好像是 Java 实战,这本书写得实在太妙了,真正的从理论到实践,从截图分析到.class字节码分析。哇,我想市场上很难买到这么精致的书了。作为一个Java爱好者,我觉得绝对值得一读。
我对此书印象最深之一的就是:equal()方法,由浅入深,经典!
还有就是同步了,其中提到了我的几个编程误区,以前如何使用同步提高性能等等,通过学习,使我对同步的认识进一步加深。
简单介绍
创建线程有两种方式:继承Thread或实现Runnable。Thread实现了Runnable接口,提供了一个空的run()方法,所以不论是继承Thread还是实现Runnable,都要有自己的run()方法。
一个线程创建后就存在,调用start()方法就开始运行(执行run()方法),调用wait进入等待或调用sleep进入休眠期,顺利运行完毕或休眠被中断或运行过程中出现异常而退出。
wait和sleep比较:
sleep方法有:sleep(long millis),sleep(long millis, long nanos),调用sleep方法后,当前线程进入休眠期,暂停执行,但该线程继续拥有监视资源的所有权。到达休眠时间后线程将继续执行,直到完成。若在休眠期另一线程中断该线程,则该线程退出。
wait方法有:wait(),wait(long timeout),wait(long timeout, long nanos),调用wait方法后,该线程放弃监视资源的所有权进入等待状态;
wait():等待有其它的线程调用notify()或notifyAll()进入调度状态,与其它线程共同争夺监视。wait()相当于wait(0),wait(0, 0)。
wait(long timeout):当其它线程调用notify()或notifyAll(),或时间到达timeout亳秒,或有其它某线程中断该线程,则该线程进入调度状态。
wait(long timeout, long nanos):相当于wait(1000000*timeout + nanos),只不过时间单位为纳秒。
线程池:
多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。
如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
一个线程池包括以下四个基本组成部分:
1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:
假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。
/** 线程池类,工作线程作为其内部类 **/
package org.ymcn.util;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
/**
* 线程池
* 创建线程池,销毁线程池,添加新任务
*
* @author obullxl
*/
public final class ThreadPool {
private static Logger logger = Logger.getLogger(ThreadPool.class);
private static Logger taskLogger = Logger.getLogger("TaskLogger");
private static boolean debug = taskLogger.isDebugEnabled();
// private static boolean debug = taskLogger.isInfoEnabled();
/* 单例 */
private static ThreadPool instance = ThreadPool.getInstance();
public static final int SYSTEM_BUSY_TASK_COUNT = 150;
/* 默认池中线程数 */
public static int worker_num = 5;
/* 已经处理的任务数 */
private static int taskCounter = 0;
public static boolean systemIsBusy = false;
private static List<Task> taskQueue = Collections
.synchronizedList(new LinkedList<Task>());
/* 池中的所有线程 */
public PoolWorker[] workers;
private ThreadPool() {
workers = new PoolWorker[5];
for (int i = 0; i < workers.length; i++) {
workers[i] = new PoolWorker(i);
}
}
private ThreadPool(int pool_worker_num) {
worker_num = pool_worker_num;
workers = new PoolWorker[worker_num];
for (int i = 0; i < workers.length; i++) {
workers[i] = new PoolWorker(i);
}
}
public static synchronized ThreadPool getInstance() {
if (instance == null)
return new ThreadPool();
return instance;
}
/**
* 增加新的任务
* 每增加一个新任务,都要唤醒任务队列
* @param newTask
*/
public void addTask(Task newTask) {
synchronized (taskQueue) {
newTask.setTaskId(++taskCounter);
newTask.setSubmitTime(new Date());
taskQueue.add(newTask);
/* 唤醒队列, 开始执行 */
taskQueue.notifyAll();
}
logger.info("Submit Task<" + newTask.getTaskId() + ">: "
+ newTask.info());
}
/**
* 批量增加新任务
* @param taskes
*/
public void batchAddTask(Task[] taskes) {
if (taskes == null || taskes.length == 0) {
return;
}
synchronized (taskQueue) {
for (int i = 0; i < taskes.length; i++) {
if (taskes[i] == null) {
continue;
}
taskes[i].setTaskId(++taskCounter);
taskes[i].setSubmitTime(new Date());
taskQueue.add(taskes[i]);
}
/* 唤醒队列, 开始执行 */
taskQueue.notifyAll();
}
for (int i = 0; i < taskes.length; i++) {
if (taskes[i] == null) {
continue;
}
logger.info("Submit Task<" + taskes[i].getTaskId() + ">: "
+ taskes[i].info());
}
}
/**
* 线程池信息
* @return
*/
public String getInfo() {
StringBuffer sb = new StringBuffer();
sb.append("\nTask Queue Size:" + taskQueue.size());
for (int i = 0; i < workers.length; i++) {
sb.append("\nWorker " + i + " is "
+ ((workers[i].isWaiting()) ? "Waiting." : "Running."));
}
return sb.toString();
}
/**
* 销毁线程池
*/
public synchronized void destroy() {
for (int i = 0; i < worker_num; i++) {
workers[i].stopWorker();
workers[i] = null;
}
taskQueue.clear();
}
/**
* 池中工作线程
*
* @author obullxl
*/
private class PoolWorker extends Thread {
private int index = -1;
/* 该工作线程是否有效 */
private boolean isRunning = true;
/* 该工作线程是否可以执行新任务 */
private boolean isWaiting = true;
public PoolWorker(int index) {
this.index = index;
start();
}
public void stopWorker() {
this.isRunning = false;
}
public boolean isWaiting() {
return this.isWaiting;
}
/**
* 循环执行任务
* 这也许是线程池的关键所在
*/
public void run() {
while (isRunning) {
Task r = null;
synchronized (taskQueue) {
while (taskQueue.isEmpty()) {
try {
/* 任务队列为空,则等待有新任务加入从而被唤醒 */
taskQueue.wait(20);
} catch (InterruptedException ie) {
logger.error(ie);
}
}
/* 取出任务执行 */
r = (Task) taskQueue.remove(0);
}
if (r != null) {
isWaiting = false;
try {
if (debug) {
r.setBeginExceuteTime(new Date());
taskLogger.debug("Worker<" + index
+ "> start execute Task<" + r.getTaskId() + ">");
if (r.getBeginExceuteTime().getTime()
- r.getSubmitTime().getTime() > 1000)
taskLogger.debug("longer waiting time. "
+ r.info() + ",<" + index + ">,time:"
+ (r.getFinishTime().getTime() - r
.getBeginExceuteTime().getTime()));
}
/* 该任务是否需要立即执行 */
if (r.needExecuteImmediate()) {
new Thread(r).start();
} else {
r.run();
}
if (debug) {
r.setFinishTime(new Date());
taskLogger.debug("Worker<" + index
+ "> finish task<" + r.getTaskId() + ">");
if (r.getFinishTime().getTime()
- r.getBeginExceuteTime().getTime() > 1000)
taskLogger.debug("longer execution time. "
+ r.info() + ",<" + index + ">,time:"
+ (r.getFinishTime().getTime() - r
.getBeginExceuteTime().getTime()));
}
} catch (Exception e) {
e.printStackTrace();
logger.error(e);
}
isWaiting = true;
r = null;
}
}
}
}
}
/** 任务接口类 **/
package org.ymcn.util;
import java.util.Date;
/**
* 所有任务接口
* 其他任务必须继承访类
*
* @author obullxl
*/
public abstract class Task implements Runnable {
// private static Logger logger = Logger.getLogger(Task.class);
/* 产生时间 */
private Date generateTime = null;
/* 提交执行时间 */
private Date submitTime = null;
/* 开始执行时间 */
private Date beginExceuteTime = null;
/* 执行完成时间 */
private Date finishTime = null;
private long taskId;
public Task() {
this.generateTime = new Date();
}
/**
* 任务执行入口
*/
public void run() {
/**
* 相关执行代码
*
* beginTransaction();
*
* 执行过程中可能产生新的任务 subtask = taskCore();
*
* commitTransaction();
*
* 增加新产生的任务 ThreadPool.getInstance().batchAddTask(taskCore());
*/
}
/**
* 所有任务的核心 所以特别的业务逻辑执行之处
*
* @throws Exception
*/
public abstract Task[] taskCore() throws Exception;
/**
* 是否用到数据库
*
* @return
*/
protected abstract boolean useDb();
/**
* 是否需要立即执行
*
* @return
*/
protected abstract boolean needExecuteImmediate();
/**
* 任务信息
*
* @return String
*/
public abstract String info();
public Date getGenerateTime() {
return generateTime;
}
public Date getBeginExceuteTime() {
return beginExceuteTime;
}
public void setBeginExceuteTime(Date beginExceuteTime) {
this.beginExceuteTime = beginExceuteTime;
}
public Date getFinishTime() {
return finishTime;
}
public void setFinishTime(Date finishTime) {
this.finishTime = finishTime;
}
public Date getSubmitTime() {
return submitTime;
}
public void setSubmitTime(Date submitTime) {
this.submitTime = submitTime;
}
public long getTaskId() {
return taskId;
}
public void setTaskId(long taskId) {
this.taskId = taskId;
}
}
发表评论
-
多种加密算法实现(JAVA)
2013-10-24 09:18 1636有短句“Sun Yat-sen University is ... -
断点续传的原理
2013-05-07 19:53 838转自:http://www.ibm.com/develope ... -
《JAVA与模式》之调停者模式
2012-06-21 20:06 651参考:http://www.cnblo ... -
Java中读取字节流并按指定编码转换成字符串的方法
2011-05-21 11:22 1463参考: http://www.blogjava.net/pen ... -
字节流编码获取原来这么复杂,但也很简单
2011-05-21 11:02 1515参考:http://www.cnblogs ... -
使用Java.util.zip下的zipOutStream和zipInStream对字节流进行压缩和解压缩
2011-05-21 10:08 1731参考:http://www.blogjava.net/ushe ... -
ActionScript与Java类型对应表
2011-05-21 09:46 1040当你使用AMF格式进行RemoteObject 调用时,肯定会 ... -
基于red5的在线视频录制实例和详细注释
2011-05-14 23:03 1586参考:http://www.ccvita.com/130.ht ... -
Java 中几种查找算法
2011-05-12 10:31 1477顺序查找说明:顺序查找适合于存储结构为顺序存储或链接存储的线性 ... -
Converting data from Java to ActionScript
2011-05-07 14:23 999On the client side, the ide ... -
java大整数相加及相乘
2011-05-04 18:34 1495import java.io.BufferedInputStr ... -
.org.hibernate.ObjectNotFoundException: No row with the given identifier exists
2011-04-20 18:09 1168说到底,就是外键关联引起的问题。 问题产生原因:有一个 ... -
java.util.ConcurrentModificationException
2011-04-19 10:07 583一般来说这个异常是容器类在遍历的时候被修改时抛出的。比 ... -
Spring+Hibernate+Flex,update、delete操作无法持久到数据库的解决办法
2011-04-17 21:42 1424这个解决办法就是才有事务机制了。。。 我是spring ... -
hibernate 注解 一对多 唯一索引
2011-04-17 02:00 2839今天被hibernate和mysql整了一下,切身感受到索引的 ... -
精通Hibernate——映射一对多关联关系
2011-04-17 01:38 1027在域模型(实体域)中,关联关系是类与类之间最普遍的关系。根据U ... -
junit实现opensessionInView保持session
2011-04-11 10:00 839参考:http://allenwei.iteye.com/bl ... -
Hibernate中cascade与inverse属性详解
2011-04-07 10:57 1059原文: 忘记存了..... ... -
HIbernate注解
2011-04-07 10:37 908Hibernate注解 文章分类:Web前端 @o ... -
Flex 通过Blazeds上传文件
2011-03-30 21:59 962本文讲的是通过Blazeds实现Flex文件上传,关于Blaz ...
相关推荐
本程序通过selenium库和random库调用Google Chrome浏览器模拟人的手工操作,通过在关键词查询框里随机输入关键词、并设置键入的时间间隔模拟人的输入行为,然后再控制浏览器随机翻页,真正像普通人一样操作浏览器规避亚马逊的防爬虫机制。根据预定的关键词列表查询产品,然后通过BeautifulSoup解析查询结果获取亚马逊产品的价格、标题、ASIN、评论等信息,并将这些产品保存为本地csv文件,方便在Excel里分析处理。
微信诗词鉴赏小程序【基于微信小程序的在线诗词鉴赏平台】是一个以微信小程序为载体,专注于古代诗词鉴赏的项目 此项目旨在打造一个便捷、全面的移动端诗词学习与交流平台,让用户能够随时随地沉浸在中华
【毕业设计】Python的Django-vue的摄影交流平台源码(完整前后端+mysql+说明文档+LW+PPT).zip
基于Matlab Simulink的三相两电平逆变器矢量控制系统的仿真波形动态分析及其性能优化研究报告,基于Matlab Simulink仿真平台下的两电平逆变器矢量控制系统动态分析及其波形研究,基于Matlab Simulink的两电平逆变器矢量控制系统的仿真波形的动态分析 不,需要的资料,文档有 ,基于Matlab; Simulink; 两电平逆变器; 矢量控制系统; 仿真波形; 动态分析,基于Simulink的逆变器矢量控制系统动态仿真分析
【达摩老生出品,必属精品,亲测校正,质量保证】 资源名:FinsDLL文件及调用手册 资源类型:程序源代码 源码说明:本人依据 Omron 通讯手册 编写的.DLL 使用 C# 开发 可以实现 对 OMRON PLC 内部寄存器 D区 M区 CIO区 HR区 字 。位 的 读写操作 以及 AR 区 字、位的读操作。使用方便 直接按照调用手册 操作步骤即可实现读写功能。 适合人群:新手及有一定经验的开发人员。内容来源于网络分享,如有侵权请联系我删除。
资源说明:https://editor.csdn.net/md/?articleId=129220710#323_oled_148 本设计的电梯系统采用的是stm32微处理器。STM32处理器是基于Cortex-M3架构的嵌入式微处理器MCU,其中Cortex-M3架构是ARM公司推出的。STM32处理器具有高速、高集成度、低功耗、高可靠性等优点。正是由于STM32处理器具有这些优点,它正适合运用于电梯控制。本设计中的电梯控制系统主要运用了STM32处理器GPIO口操作和其精确地定时功能。该电梯系统一共分6个部分,它们是 STM32处理器、电源系统、数码管显示器、键盘、LED小灯、直流电机驱动模块。这些部分是直接与STM32的GPIO口连接的,所以它们占用的GPIO口较多。 各功能模块简介: (1)电源系统:为整个系统提供+5V电源; (2)键盘:每个键位互不影响用以控制电梯运行状态; (3)LED指示小灯:用以指示小健是否被按下和电梯门开关状态; (4)4位8段数码管:用于显示电梯内部和每层电梯外部电梯所在的层数; STM32开发板:通过写入程序代码来控制电梯的运行状态。。。。。。。
推荐Matlab人脸识别源码合集(包含PCA、Adaboost、DLDA、费舍尔算法等)及多语言参考,推荐Matlab人脸识别源码合集(包含PCA、Adaboost、DLDA、费舍尔算法等多套实现),Matlab人脸识别源码6套,可运行(包括PCA算法,Adaboost算法,DLDA算法,费舍尔算法等)。 另含多套文档及JAVA,PYTHON,C#,OPENCV人脸识别源码可供参考 源码很多,请优先选择Matlab文件夹且标题里含有(推荐)标识者 ,Matlab人脸识别源码; PCA算法; Adaboost算法; DLDA算法; 费舍尔算法; JAVA,PYTHON,C#人脸识别源码; OPENCV人脸识别源码; 推荐标识; 优先选择Matlab文件夹。,Matlab人脸识别源码合集(推荐PCA、Adaboost、DLDA算法,含多套文档及跨平台源码)
分割资源UE5.3.z21重传
Labview操作者框架结合ADS与Twincat控制器:ST语言与EtherCAT总线控制工程项目资料,LabVIEW操作者框架结合ADS与Twincat控制器:Ethercat总线控制工程项目资料,labview操作者框架+ADS+twincat2(twincat3) st语言ethercat总线控制工程项目资料 twincat控制器+twincat资料 到手能用,labview界面+控制器 ,labview操作者框架; ADS; twincat2/3; st语言; ethercat总线控制; 控制器; 可用资料,LabVIEW操作者框架与TwinCAT控制器:Ethercat总线控制工程项目资料
基于观测器的LOS制导结合反步法控制:无人船艇路径跟踪控制的Fossen模型Matlab Simulink仿真效果研究,基于观测器的LOS制导结合反步法控制:无人船艇路径跟踪控制的Fossen模型Matlab Simulink仿真效果研究,无人船 无人艇路径跟踪控制 fossen模型matlab simulink效果 基于观测器的LOS制导结合反步法控制 ELOS+backstepping ,无人船; 无人艇; 路径跟踪控制; Fossen模型; Matlab Simulink效果; 基于观测器的LOS制导; 反步法控制; ELOS+backstepping,基于Fossen模型的无人船路径跟踪控制:ELOS与反步法联合控制的Matlab Simulink效果分析
基于【pmsm0512】的MATLAB Simulink永磁同步电机矢量控制策略研究与应用,基于【pmsm0512】的MATLAB Simulink永磁同步电机矢量控制策略研究与应用,【pmsm0512】MATLAB simulink永磁同步电机的矢量控制。 PMSM的矢量控制 ,PMSM; 矢量控制; MATLAB Simulink; 永磁同步电机; 0512,MATLAB Simulink PMSM矢量控制策略研究
深圳绿新威推出的GS2113S 半桥驱动芯片 应用于逆变器驱动 电机驱动等采用高压工艺
PMSM永磁同步电机矢量控制Simulink模型研究:速度环PI与滑模变结构对比,电流环PI滞环策略的建模与实现,PMSM永磁同步电机矢量控制Simulink模型研究:速度环PI与滑模变结构对比分析,电流环PI滞环方案搭建与验证,附详细说明文档及参考资料,PMSM永磁同步电机矢量控制simulink模型,包括matlab模型,两种方案对比,分别为速度环采用pi和滑模变结构对比,电流环采用pi滞环,搭建过程清晰且包含说明文档和其他附带参考资料。 ,PMSM永磁同步电机;矢量控制;Simulink模型;Matlab模型;速度环对比(PI vs 滑模变结构);电流环(PI滞环);搭建过程;说明文档;附带参考资料。,PMSM矢量控制Simulink模型:PI与滑模变结构方案对比
prov year 光缆线路长度/地区面积 安徽 2010 2.852140 4 安徽 2011 3.5921078 安徽 2012 4.3320751 安徽 2013 5.0716782 安徽 2014 5.8315897 安徽 2015 6.9423647 安徽 2016 9.9900103 安徽 2017 12.844298 安徽 2018 15.698587 安徽 20 19 16.412159 安徽 2020 17.125731 安徽 2021 17.839304 安徽 2022 19.266447 北京 2010 6 .5243206 北京 2011 8.9830551 北京 2012 11. 44179 北京 2013 13.407351 北京 2014 14.728 941 北京 2015 16.79026。内容来源于网络分享,如有侵权请联系我删除。
该资源为imutils-0.5.2.tar.gz,欢迎下载使用哦!
Matlab Simulink电机启动模型:模拟电压暂降及电能质量问题,适配IEEE 33节点模型研究,利用Matlab Simulink的电机启动模型精准模拟电压暂降等电能质量问题:适配IEEE 33节点模型,电机启动模型 Matlab simulink 可用于模拟电压暂降等电能质量问题,适配于本家的IEEE 33节点模型。 ,电机启动模型; Matlab Simulink; 电压暂降模拟; 电能质量问题; IEEE 33节点模型; 适配性。,Matlab Simulink电机启动模型:模拟电压暂降电能质量问题的适配IEEE 33节点模型
美赛教程&建模&数据分析&案例分析
台达as系列PLC程序模板:基于现场经验的车企通用模板,含多轴手动与自动流程,地址映像IO,高通用性与扩展性,快速项目实施利器。,台达as系列PLC程序模板:基于现场经验的车企通用模板,含多轴手动与自动流程,灵活高效可移植扩展,台达as系列plc程序模板。 本程序根据多年现场实际经验并参照车企通用模板编写,含6轴手动程序。 1+6(带一分支,可扩分支)自动流程程序。 io采用地址映像。 通用和可扩展性,可移植性强。 非常灵活,可为你项目实施节约大量宝贵时间。 ,台达AS系列PLC; 程序模板; 6轴手动程序; 1+6自动流程程序; IO地址映像; 通用可扩展性; 移植性强; 时间节约。,台达AS系列PLC程序模板:通用可扩展的自动化流程程序
S32系列MCU的S32K144与S32K148 Boot、网络与UDS标定程序定制服务,包含UDS烧写上位机解决方案,S32系列MCU的S32K144与S32K148的boot加载与网络通讯技术——包含UDS烧写及标定程序定制服务,S32k144,S32K148的boot,网络,uds,标定程序订做,包含uds烧写上位机 ,S32k144; S32K148; boot程序订做; 网络功能; UDS烧写; 上位机标定程序,S32系列MCU Boot网络UDS标定程序订制及UDS烧写上位机开发
CAE整车碰撞模型详解:含白车身、底盘等模块,材料曲线公开,细分模块丰富,附碰撞视频资料,CAE整车碰撞模型详解:包含白车身、底盘等多模块,材料及曲线公开,附碰撞视频资料,CAE 整车碰撞模型,模型完整,材料及曲线不加密,内含白车身,底盘,悬架,四门俩盖,前后保,仪表盘等细分模块,另有碰撞视频资料 ,CAE整车碰撞模型;模型完整性;不加密材料;内含细分模块;碰撞视频资料,完整CAE碰撞模型展示:涵盖白车身及底盘悬架等多模块,材料曲线无加密,附带碰撞视频