您当前的位置:首页 > 美文摘抄 > 内容

数据库的EXEC是什么意思,应该怎么用呢?ps.executeUpdate(); 是什么意思

本文目录

  • 数据库的EXEC是什么意思,应该怎么用呢
  • ps.executeUpdate(); 是什么意思
  • sql语句 execute,executeQuery和executeUpdate之间的区别
  • 为什么executeQuery没有返回
  • java 线程池ThreadPoolExecutor 共同完成一个任务
  • threadpoolexecutor和executorservice的区别
  • ScheduledThreadPoolExecutor删除任务,该怎么解决
  • 关于ThreadPoolExecutor线程池,该怎么处理
  • Timer和ScheduledThreadPoolExecutor的区别
  • ThreadPoolExecutor线程池

数据库的EXEC是什么意思,应该怎么用呢

sqlserver中EXEC命令有两种用法,一种是执行一个存储过程,另一种是执行一个动态的批处理1.使用系统存储过程sp_executesql运行Unicode命令字符串语法如下:sp_executesql [@stmt=] stmt[ {,[@params=] N’@parameter_name data_type [,...n]’} {,[@param1=] ’value’ [,...n]}]说明:必须先将各个包含所要运行的命令语句的Unicode字符串相加在一起,再交给系统存储过程sp_executesql来运行,而不能在sp_executesql的语句中来相加各个命令字符串。举例如下:declare @DBName nvarchar(20), @Tbname nvarchar(20), @SQLString nvarchar(500)set @DBName=N’Northwind’set @Tbname=N’Customers’set @SQLString=N’USE ’+@DBName+char(13) --char(13)换行SET @SQLString=@SQLString+N’select * from ’+@Tbname--必须先将命令字符串组合完毕后再交给sp_executesql来运行exec sp_executesql @SQLString2.使用EXECUTE命令运行命令字符串要使用EXECUTE命令来运行一个命令字符串的语法如下:EXEC[UTE] ({@string_variable|[N] ’stql_string’} [+...n])从语法看出,可以先将包含所要运行的命令的字符串赋给一个局部变量@string_variable,再使用EXECUTE命令来运行,或是直接使用EXECUTE命令去运行一个包含所要运行的命令语句的字符串。此外,您也可以将多个包含所要运行的命令语句的字符串相加在一起,再交给EXECUTE命令来一次运行。例:declare @sql nvarchar(4000) set @sql=’select * from [表] where email=’’test@163.com’’’ exec (@sql)

ps.executeUpdate(); 是什么意思

是当成功插入数据到数据库时候,这个会返回一个大于1的数字,来表明数据成功插入库之中

sql注入发生的时间,sql注入发生的阶段在sql预编译阶段,当编译完成的sql不会产生sql注入,采用jdbc操作数据时候,preparedStatement 预编译对象会对传入sql进行预编译。

那么当传入id 字符串为 “update ft_proposal set id = 3;drop table ft_proposal;“ 这种情况下就会导致sql注入删除ft_proposal这张表。

预编译语句

处理使用预编译语句之外,另一种实现方式可以采用存储过程,存储过程其实也是预编译的,存储过程是sql语句的集合,将所有预编译的sql语句编译完成后,存储在数据库上。

当传入的参数为3;drop table user;当执行时可以看见打印的sql语句为:select name from usre where id = ?;不管输入何种参数时,都可以防止sql注入,因为mybatis底层实现了预编译。

sql语句 execute,executeQuery和executeUpdate之间的区别

execute、executeQuery和executeUpdate之间的区别JDBC中Statement 接口提供了三种执行 SQL 语句的方法:executeQuery、executeUpdate 和 execute。使用哪一个方法由 SQL 语句所产生的内容决定。1》方法executeQuery 用于产生单个结果集(ResultSet)的语句,例如 SELECT 语句。 被使用最多的执行 SQL 语句的方法。这个方法被用来执行 SELECT 语句,它几乎是使用最多的 SQL 语句。但也只能执行查询语句,执行后返回代表查询结果的ResultSet对象。如://加载数据库驱动Class.forName(“com.mysql.jdbc.Driver“);//使用DriverManager获取数据库连接Connection conn = DriverManager.getConnection(“jdbc:mysql://localhost:3306/test“,“root“,“1234“);//使用Connection来创建一个Statment对象Statement stmt = conn.createStatement();//执行查询语句ResultSet rs =stmt.executeQuery(“select * from teacher“);//把查询结果输出来while (rs.next()){System.out.println(rs.getInt(1) + “/t“ + rs.getString(2));}2》方法executeUpdate用于执行 INSERT、UPDATE 或 DELETE 语句以及 SQL DDL(数据定义语言)语句,例如 CREATE TABLE 和 DROP TABLE。INSERT、UPDATE 或 DELETE 语句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一个整数(int),指示受影响的行数(即更新计数)。对于 CREATE TABLE 或 DROP TABLE 等不操作行的语句,executeUpdate 的返回值总为零。如://加载数据库驱动Class.forName(“com.mysql.jdbc.Driver“);//使用DriverManager获取数据库连接Connection conn = DriverManager.getConnection(“jdbc:mysql://localhost:3306/test“,“root“,“1234“);//使用Connection来创建一个Statment对象Statement stmt = conn.createStatement();//执行DML语句,返回受影响的记录条数return stmt.executeUpdate(sql);3》方法execute:可用于执行任何SQL语句,返回一个boolean值,表明执行该SQL语句是否返回了ResultSet。如果执行后第一个结果是ResultSet,则返回true,否则返回false。但它执行SQL语句时比较麻烦,通常我们没有必要使用execute方法来执行SQL语句,而是使用executeQuery或executeUpdate更适合,但如果在不清楚SQL语句的类型时则只能使用execute方法来执行该SQL语句了。如: //加载驱动Class.forName(driver);//获取数据库连接conn = DriverManager.getConnection(url , user , pass);//使用Connection来创建一个Statment对象stmt = conn.createStatement();//执行SQL,返回boolean值表示是否包含ResultSetboolean hasResultSet = stmt.execute(sql);//如果执行后有ResultSet结果集if (hasResultSet){//获取结果集rs = stmt.getResultSet();//ResultSetMetaData是用于分析结果集的元数据接口ResultSetMetaData rsmd = rs.getMetaData();int columnCount = rsmd.getColumnCount();//迭代输出ResultSet对象while (rs.next()){//依次输出每列的值for (int i = 0 ; i 《 columnCount ; i++ ){System.out.print(rs.getString(i + 1) + “/t“);}System.out.print(“/n“);}}else{System.out.println(“该SQL语句影响的记录有“ + stmt.getUpdateCount() + “条“);}

为什么executeQuery没有返回

返回包含给定查询所生成数据的 ResultSet 对象;永远不能为 null,如果没有查询到信息,返回一个next()为false的ResultSet 对象

java 线程池ThreadPoolExecutor 共同完成一个任务

线程池可以解决两个不同问题:由于减少了每个任务调用的开销,它们通常可以在执行大量异步任务时提供增强的性能,并且还可以提供绑定和管理资源(包括执行集合任务时使用的线程)的方法。每个ThreadPoolExecutor 还维护着一些基本的统计数据,如完成的任务数。 为了便于跨大量上下文使用,此类提供了很多可调整的参数和扩展挂钩。但是,强烈建议程序员使用较为方便的 Executors 工厂方法 Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)、Executors.newFixedThreadPool(int)(固定大小线程池)和 Executors.newSingleThreadExecutor()(单个后台线程),它们均为大多数使用场景预定义了设置。否则,在手动配置和调整此类时,使用以下指导: 核心和最大池大小ThreadPoolExecutor 将根据 corePoolSize(参见 getCorePoolSize())和 maximumPoolSize(参见getMaximumPoolSize())设置的边界自动调整池大小。当新任务在方法 execute(java.lang.Runnable) 中提交时,如果运行的线程少于 corePoolSize,则创建新线程来处理请求,即使其他辅助线程是空闲的。如果运行的线程多于corePoolSize 而少于 maximumPoolSize,则仅当队列满时才创建新线程。如果设置的 corePoolSize 和 maximumPoolSize相同,则创建了固定大小的线程池。如果将 maximumPoolSize 设置为基本的无界值(如 Integer.MAX_VALUE),则允许池适应任意数量的并发任务。在大多数情况下,核心和最大池大小仅基于构造来设置,不过也可以使用setCorePoolSize(int) 和 setMaximumPoolSize(int) 进行动态更改。 按需构造默认情况下,即使核心线程最初只是在新任务需要时才创建和启动的,也可以使用方法 prestartCoreThread()或 prestartAllCoreThreads() 对其进行动态重写。 创建新线程使用 ThreadFactory 创建新线程。如果没有另外说明,则在同一个 ThreadGroup 中一律使用Executors.defaultThreadFactory() 创建线程,并且这些线程具有相同的 NORM_PRIORITY 优先级和非守护进程状态。通过提供不同的 ThreadFactory,可以改变线程的名称、线程组、优先级、守护进程状态,等等。如果从 newThread返回 null 时 ThreadFactory 未能创建线程,则执行程序将继续运行,但不能执行任何任务。保持活动时间如果池中当前有多于 corePoolSize 的线程,则这些多出的线程在空闲时间超过 keepAliveTime 时将会终止(参见getKeepAliveTime(java.util.concurrent.TimeUnit))。这提供了当池处于非活动状态时减少资源消耗的方法。如果池后来变得更为活动,则可以创建新的线程。也可以使用方法 setKeepAliveTime(long, java.util.concurrent.TimeUnit) 动态地更改此参数。使用 Long.MAX_VALUE TimeUnit.NANOSECONDS 的值在关闭前有效地从以前的终止状态禁用空闲线程。 排队所有 BlockingQueue 都可用于传输和保持提交的任务。可以使用此队列与池大小进行交互:A. 如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队。B. 如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程。C. 如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。 排队有三种通用策略:直接提交。工作队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保持它们。在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集合时出现锁定。直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。无界队列。使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙的情况下将新任务加入队列。这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize 的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。有界队列。当使用有限的 maximumPoolSizes 时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。被拒绝的任务 当 Executor 已经关闭,并且 Executor 将有限边界用于最大线程和工作队列容量,且已经饱和时,在方法execute(java.lang.Runnable) 中提交的新任务将被拒绝。在以上两种情况下,execute 方法都将调用其RejectedExecutionHandler 的 RejectedExecutionHandler.rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor) 方法。下面提供了四种预定义的处理程序策略:A. 在默认的 ThreadPoolExecutor.AbortPolicy 中,处理程序遭到拒绝将抛出运行时 RejectedExecutionException。B. 在 ThreadPoolExecutor.CallerRunsPolicy 中,线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。C. 在 ThreadPoolExecutor.DiscardPolicy 中,不能执行的任务将被删除。D. 在 ThreadPoolExecutor.DiscardOldestPolicy 中,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)。定义和使用其他种类的 RejectedExecutionHandler 类也是可能的,但这样做需要非常小心,尤其是当策略仅用于特定容量或排队策略时。 挂钩方法此类提供 protected 可重写的 beforeExecute(java.lang.Thread, java.lang.Runnable) 和 afterExecute(java.lang.Runnable, java.lang.Throwable) 方法,这两种方法分别在执行每个任务之前和之后调用。它们可用于操纵执行环境;例如,重新初始化ThreadLocal、搜集统计信息或添加日志条目。此外,还可以重写方法 terminated() 来执行 Executor 完全终止后需要完成的所有特殊处理。 如果挂钩或回调方法抛出异常,则内部辅助线程将依次失败并突然终止。 队列维护方法 getQueue() 允许出于监控和调试目的而访问工作队列。强烈反对出于其他任何目的而使用此方法。remove(java.lang.Runnable) 和 purge() 这两种方法可用于在取消大量已排队任务时帮助进行存储回收。 一、例子 创建 TestThreadPool 类:import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class TestThreadPool { private static int produceTaskSleepTime = 2; private static int produceTaskMaxNumber = 10; public static void main(String args) { // 构造一个线程池 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3, TimeUnit.SECONDS, new ArrayBlockingQueue《Runnable》(3), new ThreadPoolExecutor.DiscardOldestPolicy()); for (int i = 1; i 《= produceTaskMaxNumber; i++) { try { String task = “task@ “ + i; System.out.println(“创建任务并提交到线程池中:“ + task); threadPool.execute(new ThreadPoolTask(task)); Thread.sleep(produceTaskSleepTime); } catch (Exception e) { e.printStackTrace(); } } } } view plainimport java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class TestThreadPool { private static int produceTaskSleepTime = 2; private static int produceTaskMaxNumber = 10; public static void main(String args) { // 构造一个线程池 ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3, TimeUnit.SECONDS, new ArrayBlockingQueue《Runnable》(3), new ThreadPoolExecutor.DiscardOldestPolicy()); for (int i = 1; i 《= produceTaskMaxNumber; i++) { try { String task = “task@ “ + i; System.out.println(“创建任务并提交到线程池中:“ + task); threadPool.execute(new ThreadPoolTask(task)); Thread.sleep(produceTaskSleepTime); } catch (Exception e) { e.printStackTrace(); } } } } 创建 ThreadPoolTask类:view plaincopy to clipboardprint?import java.io.Serializable; public class ThreadPoolTask implements Runnable, Serializable { private Object attachData; ThreadPoolTask(Object tasks) { this.attachData = tasks; } public void run() { System.out.println(“开始执行任务:“ + attachData); attachData = null; } public Object getTask() { return this.attachData; } } view plainimport java.io.Serializable; public class ThreadPoolTask implements Runnable, Serializable { private Object attachData; ThreadPoolTask(Object tasks) { this.attachData = tasks; } public void run() { System.out.println(“开始执行任务:“ + attachData); attachData = null; } public Object getTask() { return this.attachData; } } 执行结果: 创建任务并提交到线程池中:task@ 1开始执行任务:task@ 1创建任务并提交到线程池中:task@ 2开始执行任务:task@ 2创建任务并提交到线程池中:task@ 3创建任务并提交到线程池中:task@ 4开始执行任务:task@ 3创建任务并提交到线程池中:task@ 5开始执行任务:task@ 4创建任务并提交到线程池中:task@ 6创建任务并提交到线程池中:task@ 7创建任务并提交到线程池中:task@ 8开始执行任务:task@ 5开始执行任务:task@ 6创建任务并提交到线程池中:task@ 9开始执行任务:task@ 7创建任务并提交到线程池中:task@ 10开始执行任务:task@ 8开始执行任务:task@ 9开始执行任务:task@ 10ThreadPoolExecutor配置一、ThreadPoolExcutor为一些Executor提供了基本的实现,这些Executor是由Executors中的工厂 newCahceThreadPool、newFixedThreadPool和newScheduledThreadExecutor返回的。 ThreadPoolExecutor是一个灵活的健壮的池实现,允许各种各样的用户定制。二、线程的创建与销毁1、核心池大小、最大池大小和存活时间共同管理着线程的创建与销毁。2、核心池的大小是目标的大小;线程池的实现试图维护池的大小;即使没有任务执行,池的大小也等于核心池的大小,并直到工作队列充满前,池都不会创建更多的线程。如果当前池的大小超过了核心池的大小,线程池就会终止它。3、最大池的大小是可同时活动的线程数的上限。4、如果一个线程已经闲置的时间超过了存活时间,它将成为一个被回收的候选者。5、newFixedThreadPool工厂为请求的池设置了核心池的大小和最大池的大小,而且池永远不会超时6、newCacheThreadPool工厂将最大池的大小设置为Integer.MAX_VALUE,核心池的大小设置为0,超时设置为一分钟。这样创建了无限扩大的线程池,会在需求量减少的情况下减少线程数量。三、管理1、 ThreadPoolExecutor允许你提供一个BlockingQueue来持有等待执行的任务。任务排队有3种基本方法:无限队列、有限队列和同步移交。2、 newFixedThreadPool和newSingleThreadExectuor默认使用的是一个无限的 LinkedBlockingQueue。如果所有的工作者线程都处于忙碌状态,任务会在队列中等候。如果任务持续快速到达,超过了它们被执行的速度,队列也会无限制地增加。稳妥的策略是使用有限队列,比如ArrayBlockingQueue或有限的LinkedBlockingQueue以及 PriorityBlockingQueue。3、对于庞大或无限的池,可以使用SynchronousQueue,完全绕开队列,直接将任务由生产者交给工作者线程4、可以使用PriorityBlockingQueue通过优先级安排任务

threadpoolexecutor和executorservice的区别

ExecutorService中submit和execute的区别有三点: 1、接收的参数不同 2、submit有返回值,而execute没有 用到返回值的例子,比如说应用中有很多个做validation的task,用户希望所有的task执行完,然后每个task告诉主程序执行结果

ScheduledThreadPoolExecutor删除任务,该怎么解决

这时候想删除其中一个任务,看了下API,ScheduledThreadPoolExecutor继承ThreadPoolExecutor类,此里面有个:-------------------------------------boolean remove(Runnable task)从执行程序的内部队列中移除此任务(如果存在),从而如果尚未开始,则其不再运行。-------------------------------------我利用下面方法返回任务列表,执行其contains方法,都表示任务列表里面不包含我的任务。-------------------------------------BlockingQueue《Runnable getQueue()返回此执行程序使用的任务队列。-------------------------------------------解决的方法--------------------------------------------------------任务列队里的任务实际上对原始的任务做了包装,所以你删除任务的参数必须是你调用scheduleAtFixedRate返回的参数。------解决的方法--------------------------------------------------------API对此方法有一个说明:此方法可用作取消方案的一部分。它可能无法移除在放置到内部队列之前已经转换为其他形式的任务。例如,使用 submit 输入的任务可能被转换为维护 Future 状态的形式。

关于ThreadPoolExecutor线程池,该怎么处理

用线程池编写多线程程序时,当所有任务完成时,要做一些统计的工作。而统计工作必须要在所有任务完成才能做。所以要让主线程等待所有任务完成。可以使用ThreadPoolExecutor.awaitTermination(long timeout, TimeUnit unit)。

Timer和ScheduledThreadPoolExecutor的区别

在实际应用中,有时候我们需要创建一些个延迟的、并具有周期性的任务,比如,我们希望当我们的程序启动后每隔1小时就去做一次日志记录。在JDK中提供了两种方法去创建延迟周期性任务。TimerTimer是java.util包下的一个类,在JDK1.3的时候被引入,Timer只是充当了一个执行者的角色,真正的任务逻辑是通过一个叫做TimerTask的抽象类完成的,TimerTask也是java.util包下面的类,它是一个实现了Runnable接口的抽象类,包含一个抽象方法run( )方法,需要我们自己去提供具体的业务实现。Timer类对象是通过其schedule方法执行TimerTask对象中定义的业务逻辑,并且schedule方法拥有多个重载方法提供不同的延迟与周期性服务。下面是利用Timer去创建的一个延时周期性任务import java.text.SimpleDateFormat;import java.util.Date;import java.util.Timer;import java.util.TimerTask;public class TestTimer { public static void main(String args) { String time = new SimpleDateFormat(“HH:mm:ss“).format(new Date()); System.out.println(“Start time : “ + time); Timer timer = new Timer(); TimerTask task = new TimerTask() { @Override public void run() { // TODO Auto-generated method stub String time = new SimpleDateFormat(“HH:mm:ss“).format(new Date()); System.out.println(“Now Time : “ + time); } }; //end task timer.schedule(task, 2000, 3000); } }程序的输出:Start time : 21:36:08Now Time : 21:36:10Now Time : 21:36:13Now Time : 21:36:16Now Time : 21:36:19ScheduledThreadPoolExecutor在JDK1.5的时候在java.util.concurrent并发包下引入了ScheduledThreadPoolExecutor类,引入它的原因是因为Timer类创建的延迟周期性任务存在一些缺陷, ScheduledThreadPoolExecutor继承了ThreadPoolExecutor,并且实现了ScheduledExecutorService接口, ScheduledThreadPoolExecutor也是通过schedule方法执行Runnable任务的。我们用 ScheduledThreadPoolExecutor来实现和上述Timer一样的功能import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.ScheduledThreadPoolExecutor;import java.util.concurrent.TimeUnit;public class TestScheduledThreadPoolExecutor { public static void main(String args) { String time = new SimpleDateFormat(“HH:mm:ss“).format(new Date()); System.out.println(“Start time : “ + time); ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5); //创建5个执行线程 Runnable runnable = new Runnable() { @Override public void run() { // TODO Auto-generated method stub String time = new SimpleDateFormat(“HH:mm:ss“).format(new Date()); System.out.println(“Now Time : “ + time); } }; executor.scheduleWithFixedDelay(runnable, 2, 3, TimeUnit.SECONDS); } }程序的输出:Start time : 22:12:25Now Time : 22:12:27Now Time : 22:12:30Now Time : 22:12:33Now Time : 22:12:36这样看来Timer和 ScheduledThreadPoolExecutor好像没有声明差别,但是 ScheduledThreadPoolExecutor的引入正是由于Timer类存在的一些不足,并且在JDK1.5或更高版本中,几乎没有利用继续使用Timer类,下面说明Timer存在的一些缺点。单线程Timer类是通过单线程来执行所有的TimerTask任务的,如果一个任务的执行过程非常耗时,将会导致其他任务的时效性出现问题。而 ScheduledThreadPoolExecutor是基于线程池的多线程执行任务,不会存在这样的问题。这里我们通过让Timer来执行两个TimerTask任务来说明,其中一个TimerTask的执行过程是耗时的,加入需要2秒。import java.text.SimpleDateFormat;import java.util.Date;import java.util.Timer;import java.util.TimerTask;public class SingleThreadTimer { public static void main(String args) { String time = new SimpleDateFormat(“HH:mm:ss“).format(new Date()); System.out.println(“Start time : “ + time); Timer timer = new Timer(); TimerTask task1 = new TimerTask() { @Override public void run() { // TODO Auto-generated method stub String time = new SimpleDateFormat(“HH:mm:ss“).format(new Date()); System.out.println(“Task1 time : “ + time); } }; TimerTask task2 = new TimerTask() { @Override public void run() { // TODO Auto-generated method stub try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } String time = new SimpleDateFormat(“HH:mm:ss“).format(new Date()); System.out.println(“task2 time : “ + time); } }; timer.schedule(task1, 2000, 1000); timer.schedule(task2, 2000, 3000); } }这里定义了两个任务,任务1,程序启动2秒后每隔1秒运行一次,任务2,程序启动2秒后,每隔3秒运行1次,然后让Timer同时运行这两个任务程序的输出如下:Start time : 22:22:37Task1 time : 22:22:39task2 time : 22:22:41Task1 time : 22:22:41Task1 time : 22:22:42task2 time : 22:22:44Task1 time : 22:22:44Task1 time : 22:22:45task2 time : 22:22:47Task1 time : 22:22:47Task1 time : 22:22:48可以分析,无论是任务1还是任务2都没有按照我们设定的预期进行运行,造成这个现象的原因就是Timer类是单线程的。Timer线程不捕获异常Timer类中是不捕获异常的,假如一个TimerTask中抛出未检查异常(P.S: java中异常分为两类:checked exception(检查异常)和unchecked exception(未检查异常),对于未检查异常也叫RuntimeException(运行时异常). ),Timer类将不会处理这个异常而产生无法预料的错误。这样一个任务抛出异常将会导致整个Timer中的任务都被取消,此时已安排但未执行的TimerTask也永远不会执行了,新的任务也不能被调度(所谓的“线程泄漏”现象)。下面就已常见的RuntimeException,ArrayIndexOutOfBoundsException数组越界异常,来演示这个缺点:import java.text.SimpleDateFormat;import java.util.Date;import java.util.Timer;import java.util.TimerTask;public class TestTimerTask { public static void main(String args) { System.out.println(new SimpleDateFormat(“HH:mm:ss“).format(new Date())); Timer timer = new Timer(); TimerTask task1 = new TimerTask() { @Override public void run() { System.out.println(“1: “ + new SimpleDateFormat(“HH:mm:ss“).format(new Date())); } }; TimerTask task2 = new TimerTask() { @Override public void run() { int arr = {1,2,3,4,5}; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } int index = (int)(Math.random()*100); System.out.println(arr[index]); System.out.println(“2: “ + new SimpleDateFormat(“HH:mm:ss“).format(new Date())); } }; timer.schedule(task1, 2000, 3000); timer.schedule(task2, 2000, 1000); } }程序会在运行过程中抛出数组越界异常,并且整个程序都会被终止,原来完好的任务1也被终止了。基于绝对时间Timer类的调度是基于绝对的时间的,而不是相对的时间,因此Timer类对系统时钟的变化是敏感的,举个例子,加入你希望任务1每个10秒执行一次,某个时刻,你将系统时间提前了6秒,那么任务1就会在4秒后执行,而不是10秒后。在 ScheduledThreadPoolExecutor,任务的调度是基于相对时间的,原因是它在任务的内部 存储了该任务距离下次调度还需要的时间(使用的是基于 System#nanoTime实现的相对时间 ,不会因为系统时间改变而改变,如距离下次执行还有10秒,不会因为将系统时间调前6秒而变成4秒后执行)。基于以上3个弊端,在JDK1.5或以上版本中,我们几乎没有理由继续使用Timer类,ScheduledThreadPoolExecutor可以很好的去替代Timer类来完成延迟周期性任务。

ThreadPoolExecutor线程池

当我们需要实现并发、异步等操作时,可以使用ThreadPoolExecutor。

ThreadPoolExecutor

线程池:

系统中,我们创建(extend Thread/implement Runnable)、销毁(正常run方法完成后线程终止)线程的代价是比较高昂的。如果频繁地创建和销毁进程,会大大降低系统运行效率和吞吐量。线程池使得线程可以被复用,避免了线程频繁创建和销毁的开销,提高系统的运行效率和吞吐量。

实例

ThreadPoolExecutor.execute(new Runnable () {});

相关概念:

Task任务:new Runnable () {}任务就是一个Runnable的对象,任务的执行方法就是该对象的run方法。

缓冲队列:workQueue

一个阻塞队列。

BlockingQueue《Runnable》 workQueue;

corePoolSize:核心线程数核心线程会一直存活,即使没有任务需要执行。当线程数小于核心线程数时(还未满,就会一直增),即使有线程空闲,线程池也会优先创建新线程处理。

maxPoolSize:最大线程数当线程数大于corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务,直到线程数量达到maxPoolSize。

execute(Runnable)

通过execute将一个任务交由线程池管理。

当一个任务通过execute方法欲添加到线程池时,线程池采用的策略如下(即添加任务的策略):

1、如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。

2、如果此时线程池中的数量等于corePoolSize,但是缓冲队列workQueue未满,那么任务被放入缓冲队列。

3、如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。

4、如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过handler所指定的策略来处理此任务。

如下图:

希望对您有所帮助!~


声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,谢谢。

上一篇: 网页制作的步骤(网页制作有什么关键步骤)

下一篇: publicize(“炒作“用英语怎么说谢谢)



推荐阅读

网站内容来自网络,如有侵权请联系我们,立即删除! | 软文发布 | 粤ICP备2021106084号