当前位置: 首页 > news >正文

有什么网站做统计图的/优化大师怎么样

有什么网站做统计图的,优化大师怎么样,铁岭做网站公司哪家好,商城网站类建设哪家好如果外部代码能在某个操作正常完成之前将其置入“完成”状态,那么这个操作就可以称为可取消的(Cancellable)。取消某个操作的原因很多: 用户请求取消。用户点击图形界面程序中的“取消”按钮,或者通过管理接口来发出取消请求,例如JMX (Java …

如果外部代码能在某个操作正常完成之前将其置入“完成”状态,那么这个操作就可以称为可取消的(Cancellable)。取消某个操作的原因很多:

用户请求取消。用户点击图形界面程序中的“取消”按钮,或者通过管理接口来发出取消请求,例如JMX (Java Management Extensions)。

有时间限制的操作。例如,某个应用程序需要在有限时间内搜索问题空间,并在这个时间内选择最佳的解决方案。当计时器超时时,需要取消所有正在搜索的任务。

应用程序事件。例如,应用程序对某个问题空间进行分解并搜索,从而使不同的任务可以搜索问题空间中的不同区域。当其中一个任务找到了解决方案时,所有其他仍在搜索的任务都

虽然Thread. stop和suspend等方法提供了这样的机制,但由于存在着一些严重的缺陷,因此应该避免使用。请参见http://java.sun.com/j2se/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html了解对这些问题的详细说明。

将被取消。

错误。网页爬虫程序搜索相关的页面,并将页面或摘要数据保存到硬盘。当一个爬虫任务发生错误时(例如,磁盘空间已满),那么所有搜索任务都会取消,此时可能会记录它们的当前状态,以便稍后重新启动。

关闭。当一个程序或服务关闭时,必须对正在处理和等待处理的工作执行某种操作。在平缓的关闭过程中,当前正在执行的任务将继续执行直到完成,而在立即关闭过程中,当前的任务则可能取消。

在Java 中没有一种安全的抢占式方法来停止线程,因此也就没有安全的抢占式方法来停止任务。只有一些协作式的机制,使请求取消的任务和代码都遵循一种协商好的协议。

其中一种协作机制能设置某个“已请求取消(Cancellation Requested)”标志,而任务将定期地查看该标志。如果设置了这个标志,那么任务将提前结束。程序清单7-1中就使用了这项技术,其中的PrimeGenerator 持续地枚举素数,直到它被取消。cancel方法将设置cancelled标志,并且主循环在搜索下一个素数之前会首先检查这个标志。(为了使这个过程能可靠地工作,标志cancelled必须为volatile 类型。)

public class PrimeGenerator implements Runnable {

@GuardedBy("this")

private final List<BigInteger>primes

=new ArrayList<BigInteger>();

private volatile boolean cancelled;

public void run(){

BigInteger p =BigInteger. ONE;

while (Icancelled ){

p =p. nextProbablePrime();

synchronized (this){

primes. add(p);

}

}

}

public void cancel(){cancelled =true;}

public synchronized List<BigInteger>get(){

return new ArrayList<BigInteger>(primes);

}

}

                                                                      

程序清单7-2 给出了这个类的使用示例,即让素数生成器运行1秒钟后取消。素数生成器通常并不会刚好在运行1秒钟后停止,因为在请求取消的时刻和run方法中循环执行下一次检查之间可能存在延迟。cancel方法由finally 块调用,从而确保即使在调用sleep 时被中断也能取消素数生成器的执行。如果cancel 没有被调用,那么搜索素数的线程将永远运行下去,不断消耗CPU的时钟周期,并使得JVM 不能正常退出。

                                 程序清单7-2      一个仅运行一秒钟的素数生成器                  

List<BigInteger>aSecond0fPrimes() throws InterruptedException {

PrimeGenerator generator =new PrimeGenerator();

new Thread (generator). start();

try {

SECONDS. sleep(1);

}finally {

generator. cancel();

}

return generator. get();

}

一个可取消的任务必须拥有取消策略(Cancellation Policy),在这个策略中将详细地定义取消操作的“How”、“When”以及“What”,即其他代码如何(How)请求取消该任务,任务在何时(When)检查是否已经请求了取消,以及在响应取消请求时应该执行哪些(What)操作。

考虑现实世界中停止支付(Stop-Payment)支票的示例。银行通常都会规定如何提交一个停止支付的请求,在处理这些请求时需要做出哪些响应性保证,以及当支付中断后需要遵守哪些流程(例如通知该事务中涉及的其他银行,以及对付款人的账户进行费用评估)。这些流程和保证放在一起就构成了支票支付的取消策略。

PrimeGenerator 使用了一种简单的取消策略:客户代码通过调用cancel来请求取消,PrimeGenerator在每次搜索素数前首先检查是否存在取消请求,如果存在则退出。

 中断

PrimeGenerator中的取消机制最终会使得搜索素数的任务退出,但在退出过程中需要花费一定的时间。然而,如果使用这种方法的任务调用了一个阻塞方法,例如BlockingQueue. put,那么可能会产生一个更严重的问题——任务可能永远不会检查取消标志,因此永远不会结束。

在程序清单7-3 中的BrokenPrimeProducer就说明了这个问题。生产者线程生成素数,并将它们放入一个阻塞队列。如果生产者的速度超过了消费者的处理速度,队列将被填满, put 方法也会阻塞。当生产者在put方法中阻塞时,如果消费者希望取消生产者任务,那么将发生什么情况?它可以调用cancel方法来设置cancelled标志,但此时生产者却永远不能检查这个标志,因为它无法从阻塞的put 方法中恢复过来(因为消费者此时已经停止从队列中取出素数,所以put 方法将一直保持阻塞状态)。

th'is. queue =queue;

}

public void run(){

try {

BigInteger p =BigInteger. ONE;

while (Icancelled)

queue. put(p=p. nextProbablePrime());

}catch (InterruptedException consumed){}

}

public void cancel(){cancelled =true;}

}

void consumePrimes() throws InterruptedException {

BlockingQueue<BigInteger>primes =···;

BrokenPrimeProducer producer =new BrokenPrimeProducer(primes);

producer. start();

try {

while (needMorePrimes())

consume(primes. take());

}finally {

producer. cancel();

}

}

                                                                      

一些特殊的阻塞库的方法支持中断。线程中断是一种协作机制,线程可以通过这种机制来通知另一个线程,告诉它在合适的或者可能的情况下停止当前工作,并转而执行其他的工作。

在Java的API或语言规范中,并没有将中断与任何取消语义关联起来,但实际上,如果在取消之外的其他操作中使用中断,那么都是不合适的,并且很难支撑起更大的应用。

每个线程都有一个boolean类型的中断状态。当中断线程时,这个线程的中断状态将被设置为true。在Thread 中包含了中断线程以及查询线程中断状态的方法,如程序清单7-4所示。interrupt方法能中断目标线程,而isInterrupted 方法能返回目标线程的中断状态。静态的interrupted 方法将清除当前线程的中断状态,并返回它之前的值,这也是清除中断状态的唯一方法。

                                 程序清单7-4               Thread 中的中断方法                  

public class Thread {

public void interrupt(){…}

public boolean isInterrupted(){……}

public static boolean interrupted(){…}

...

                                                                                             

阻塞库方法,例如Thread. sleep 和Object. wait等,都会检查线程何时中断,并且在发现中断时提前返回。它们在响应中断时执行的操作包括:清除中断状态,抛出InterruptedException,表示阻塞操作由于中断而提前结束。JVM 并不能保证阻塞方法检测到中断的速度,但在实际情况中响应速度还是非常快的。

当线程在非阻塞状态下中断时,它的中断状态将被设置,然后根据将被取消的操作来检查中断状态以判断发生了中断。通过这样的方法,中断操作将变得“有黏性”——如果不触发InterruptedException,那么中断状态将一直保持,直到明确地清除中断状态。

调用interrupt并不意味着立即停止目标线程正在进行的工作,而只是传递了请求中断的消息。

对中断操作的正确理解是:它并不会真正地中断一个正在运行的线程,而只是发出中断请求,然后由线程在下一个合适的时刻中断自己。(这些时刻也被称为取消点)。有些方法,例如wait、sleep 和join等,将严格地处理这种请求,当它们收到中断请求或者在开始执行时发现某个已被设置好的中断状态时,将抛出一个异常。设计良好的方法可以完全忽略这种请求,只要它们能使调用代码对中断请求进行某种处理。设计糟糕的方法可能会屏蔽中断请求,从而导致调用栈中的其他代码无法对中断请求作出响应。

在使用静态的interrupted 时应该小心,因为它会清除当前线程的中断状态。如果在调用interrupted 时返回了true,那么除非你想屏蔽这个中断,否则必须对它进行处理——可以抛出InterruptedException,或者通过再次调用interrupt来恢复中断状态,如程序清单5-10 所示。

BrokenPrimeProducer 说明了一些自定义的取消机制无法与可阻塞的库函数实现良好交互的原因。如果任务代码能够响应中断,那么可以使用中断作为取消机制,并且利用许多库类中提供的中断支持。

通常,中断是实现取消的最合理方式。

BrokenPrimeProducer 中的问题很容易解决(和简化):使用中断而不是boolean标志来请求取消,如程序清单7-5所示。在每次迭代循环中,有两个位置可以检测出中断:在阻塞的put 方法调用中,以及在循环开始处查询中断状态时。由于调用了阻塞的put 方法,因此这里并不一定需要进行显式的检测,但执行检测却会使PrimeProducer 对中断具有更高的响应性,因为它是在启动寻找素数任务之前检查中断的,而不是在任务完成之后。如果可中断的阻塞方法的调用频率并不高,不足以获得足够的响应性,那么显式地检测中断状态能起到一定的帮助作用。

                                    程序清单7-5                     通过中断来取消                        

class PrimeProducer extends Thread {

private final BlockingQueue<BigInteger>queue;

PrimeProducer(BlockingQueue<BigInteger>queue){

this. queue =queue;

}

public void run(){

try {

BigInteger p =BigInteger. ONE;

while (!Thread. currentThread(). isInterrupted())

queue. put (p =p. nextProbablePrime());

}catch (InterruptedException consumed){

/*   允许线程退出      */

}

}

public void cancel(){interrupt();}

}

                                                                     

中断策略

'正如任务中应该包含取消策略一样,线程同样应该包含中断策略。中断策略规定线程如何解释某个中断请求——当发现中断请求时,应该做哪些工作(如果需要的话),哪些工作单元对于中断来说是原子操作,以及以多快的速度来响应中断。

最合理的中断策略是某种形式的线程级(Thread-Level)取消操作或服务级(Service-Level)取消操作:尽快退出,在必要时进行清理,通知某个所有者该线程已经退出。此外还可以建立其他的中断策略,例如暂停服务或重新开始服务,但对于那些包含非标准中断策略的线程或线程池,只能用于能知道这些策略的任务中。

区分任务和线程对中断的反应是很重要的。一个中断请求可以有一个或多个接收者——中断线程池中的某个工作者线程,同时意味着“取消当前任务”和“关闭工作者线程”。

任务不会在其自己拥有的线程中执行,而是在某个服务(例如线程池)拥有的线程中执行。对于非线程所有者的代码来说(例如,对于线程池而言,任何在线程池实现以外的代码),应该小心地保存中断状态,这样拥有线程的代码才能对中断做出响应,即使“非所有者”代码也可以做出响应。(当你为一户人家打扫房屋时,即使主人不在,也不应该把在这段时间内收到的邮件扔掉,而应该把邮件收起来,等主人回来以后再交给他们处理,尽管你可以阅读他们的杂志。)

这就是为什么大多数可阻塞的库函数都只是抛出InterruptedException 作为中断响应。它们永远不会在某个由自己拥有的线程中运行,因此它们为任务或库代码实现了最合理的取消策略:尽快退出执行流程,并把中断信息传递给调用者,从而使调用栈中的上层代码可以采取进一步的操作。

当检查到中断请求时,任务并不需要放弃所有的操作——它可以推迟处理中断请求,并直到某个更合适的时刻。因此需要记住中断请求,并在完成当前任务后抛出InterruptedException或者表示已收到中断请求。这项技术能够确保在更新过程中发生中断时,数据结构不会被破坏。

任务不应该对执行该任务的线程的中断策略做出任何假设,除非该任务被专门设计为在服务中运行,并且在这些服务中包含特定的中断策略。无论任务把中断视为取消,还是其他某个中断响应操作,都应该小心地保存执行线程的中断状态。如果除了将InterruptedException 传递给调用者外还需要执行其他操作,那么应该在捕获InterruptedException之后恢复中断状态:

Thread. currentThread(). interrupt();

正如任务代码不应该对其执行所在的线程的中断策略做出假设,执行取消操作的代码也不应该对线程的中断策略做出假设。线程应该只能由其所有者中断,所有者可以将线程的中断策略信息封装到某个合适的取消机制中,例如关闭(shutdown)方法。

由于每个线程拥有各自的中断策略,因此除非你知道中断对该线程的含义,否则就不应该中断这个线程。

批评者曾嘲笑Java 的中断功能,因为它没有提供抢占式中断机制,而且还强迫开发人员必须处理InterruptedException。然而,通过推迟中断请求的处理,开发人员能制定更灵活的中断策略,从而使应用程序在响应性和健壮性之间实现合理的平衡。

   响应中断

在5.4节中,当调用可中断的阻塞函数时,例如Thread. sleep 或BlockingQueue. put等,有两种实用策略可用于处理InterruptedException:

·传递异常(可能在执行某个特定于任务的清除操作之后),从而使你的方法也成为可中断的阻塞方法。

·恢复中断状态,从而使调用栈中的上层代码能够对其进行处理。

传递InterruptedException 与将InterruptedException添加到throws子句中一样容易,如程序清单7-6中的getNextTask所示。

                  程序清单7-6将InterruptedException传递给调用者                              

BlockingQueue<Task>queue;

public Task getNextTask() throws InterruptedException {`

如果不想或无法传递InterruptedException(或许通过Runnable 来定义任务),那么需要寻找另一种方式来保存中断请求。一种标准的方法就是通过再次调用interrupt来恢复中断状态。你不能屏蔽InterruptedException,例如在catch 块中捕获到异常却不做任何处理,除非在你的代码中实现了线程的中断策略。虽然PrimeProducer 屏蔽了中断,但这是因为它已经知道线程将要结束,因此在调用栈中已经没有上层代码需要知道中断信息。由于大多数代码并不知道它们将在哪个线程中运行,因此应该保存中断状态。

只有实现了线程中断美味的代码才可以拼成中断铸装。在常规的任务和群代码中标

不应该屏蔽中断请求

对于一些不支持取消但仍可以调用可中断阻塞方法的操作,它们必须在循环中调用这些方法,并在发现中断后重新尝试。在这种情况下,它们应该在本地保存中断状态,并在返回前恢复状态而不是在捕获InterruptedException时恢复状态,如程序清单7-7所示。如果过早地设置中断状态,就可能引起无限循环,因为大多数可中断的阻塞方法都会在入口处检查中断状态,并且当发现该状态已被设置时会立即抛出InterruptedException。(通常,可中断的方法会在阻塞或进行重要的工作前首先检查中断,从而尽快地响应中断)。

public Task getNextTask(BlockingQueue<Taskgt;queue){

boolean interrupted =false;

try {

while (true){

try {

return queue. take();

}catch (InterruptedException e){

interrupted =true;

//重新尝试

}

}

}finally {

if (interrupted)

Thread. currentThread(). interrupt();

}

}

如果代码不会调用可中断的阻塞方法,那么仍然可以通过在任务代码中轮询当前线程的中断状态来响应中断。要选择合适的轮询频率,就需要在效率和响应性之间进行权衡。如果响应性要求较高,那么不应该调用那些执行时间较长并且不响应中断的方法,从而对可调用的库代码进行一些限制。

在取消过程中可能涉及除了中断状态之外的其他状态。中断可以用来获得线程的注意,并且由中断线程保存的信息,可以为中断的线程提供进一步的指示。(当访问这些信息时,要确保使用同步。)

例如,当一个由ThreadPoolExecutor 拥有的工作者线程检测到中断时,它会检查线程池是否正在关闭。如果是,它会在结束之前执行一些线程池清理工作,否则它可能创建一个新线程将线程池恢复到合理的规模。

  示例:计时运行

许多问题永远也无法解决(例如,枚举所有的素数),而某些问题,能很快得到答案,也可能永远得不到答案。在这些情况下,如果能够指定“最多花10分钟搜索答案”或者“枚举出在10分钟内能找到的答案”,那么将是非常有用的。

程序清单7-2 中的aSecondOfPrimes方法将启动一个PrimeGenerator,并在1秒钟后中断。尽管PrimeGenerator可能需要超过1秒的时间才能停止,但它最终会发现中断,然后停止,并使线程结束。在执行任务时的另一个方面是,你希望知道在任务执行过程中是否会抛出异常。

如果PrimeGenerator 在指定时限内抛出了一个未检查的异常,那么这个异常可能会被忽略,因为素数生成器在另一个独立的线程中运行,而这个线程并不会显式地处理异常。

在程序清单7-8 中给出了在指定时间内运行一个任意的Runnable的示例。它在调用线程中运行任务,并安排了一个取消任务,在运行指定的时间间隔后中断它。这解决了从任务中抛出未检查异常的问题,因为该异常会被timedRun的调用者捕获。

cancelExec. schedule(new Runnable(){

public void run(){taskThread. interrupt();}

}, timeout, unit);

r. run ( ) ;

}

这是一种非常简单的方法,但却破坏了以下规则:在中断线程之前,应该了解它的中断策略。由于timedRun可以从任意一个线程中调用,因此它无法知道这个调用线程的中断策略。如果任务在超时之前完成,那么中断timedRun所在线程的取消任务将在timedRun返回到调用者之后启动。我们不知道在这种情况下将运行什么代码,但结果一定是不好的。(可以使用schedule返回的ScheduledFuture 来取消这个取消任务以避免这种风险,这种做法虽然可行,但却非常复杂。)

而且,如果任务不响应中断,那么timedRun会在任务结束时才返回,此时可能已经超过了指定的时限(或者还没有超过时限)。如果某个限时运行的服务没有在指定的时间内返回,那么将对调用者带来负面影响。

在程序清单7-9 中解决了aSecondOfPrimes的异常处理问题以及之前解决方案中的问题。执行任务的线程拥有自己的执行策略,即使任务不响应中断,限时运行的方法仍能返回到它的调用者。在启动任务线程之后,timedRun将执行一个限时的join 方法。在join 返回后,它将检查任务中是否有异常抛出,如果有的话,则会在调用timedRun的线程中再次抛出该异常。由于Throwable将在两个线程之间共享,因此该变量被声明为volatile类型,从而确保安全地将其从任务线程发布到timedRun线程。

public void run(){

try  {  r. run() ;}

catch (Throwable t){this. t =t;}

}

void rethrow(){

if  ( t != null)

throw launderThrowable(t);

}

}

RethrowableTask task =new RethrowableTask();

final Thread taskThread =new Thread (task);

taskThread. start();

cancelExec. schedule(new Runnable(){

public void run(){taskThread. interrupt();}

}, timeout, unit);

taskThread. join(unit. toMillis(timeout));

task. rethrow();

}

                                                                      

在这个示例的代码中解决了前面示例中的问题,但由于它依赖于一个限时的join,因此存在着join的不足:无法知道执行控制是因为线程正常退出而返回还是因为join 超时而返回。

 通过Future 来实现取消

我们已经使用了一种抽象机制来管理任务的生命周期,处理异常,以及实现取消,即Future。通常,使用现有库中的类比自行编写更好,因此我们将继续使用Future和任务执行框架来构建timedRun。

ExecutorService. submit将返回一个Future 来描述任务。Future拥有一个cancel 方法,该方法带有一个boolean 类型的参数mayInterruptIfRunning,表示取消操作是否成功。(这只是表示任务是否能够接收中断,而不是表示任务是否能检测并处理中断。)如果mayInterruptIfRunning 为true 并且任务当前正在某个线程中运行,那么这个线程能被中断。如果这个参数为false,那么意味着“若任务还没有启动,就不要运行它”,这种方式应该用于那些不处理中断的任务中。

除非你清楚线程的中断策略,否则不要中断线程,那么在什么情况下调用cancel可以将参数指定为true?执行任务的线程是由标准的Executor 创建的,它实现了一种中断策略使得任务可以通过中断被取消,所以如果任务在标准Executor中运行,并通过它们的Future 来取消任务,那么可以设置mayInterruptIfRunning。当尝试取消某个任务时,不宜直接中断线程池,因为你并不知道当中断请求到达时正在运行什么任务——只能通过任务的Future 来实现取消。这也是在编写任务时要将中断视为一个取消请求的另一个理由:可以通过任务的Future来取消它们。

程序清单7-10 给出了另一个版本的timedRun:将任务提交给一个ExecutorService,并通过一个定时的Future. get 来获得结果。如果get 在返回时抛出了一个TimeoutException,那么任务将通过它的Future来取消。(为了简化代码,这个版本的timedRun在finally 块中将直接调用Future. cancel,因为取消一个已完成的任务不会带来任何影响。)如果任务在被取消前就抛出一个异常,那么该异常将被重新抛出以便由调用者来处理异常。在程序清单7-10中还给出了另一种良好的编程习惯:取消那些不再需要结果的任务。(在程序清单6-13和程序清单6-16 中使用了相同的技术。)

            程序清单7-10通过 Future 来取消任务                        

public static void timedRun(Runnable r,

long timeout,TimeUnit unit)

throws InterruptedException {

Future<?>task =taskExec. submit(r);

try {

task. get(timeout, unit);

}catch (Timeout Exception e){

//   接下来任务将被取消

}catch (ExecutionException e){

∥如果在任务中抛出了异常,那么重新抛出该异常

throw launderThrowable(e. getCause());

}finally {

//如果任务已经结束,那么执行取消操作也不会带来任何影响

task. cancel(true);//如果任务正在运行,那么将被中断

}

}

                                                                      

当Future. get 抛出InterruptedException或TimeoutException时,如果你知道不再需要结果,那么就可以调用Future. cancel来取消任务。

 处理不可中断的阻塞

在Java 库中,许多可阻塞的方法都是通过提前返回或者抛出InterruptedException来响应中断请求的,从而使开发人员更容易构建出能响应取消请求的任务。然而,并非所有的可阻塞方法或者阻塞机制都能响应中断;如果一个线程由于执行同步的Socket I/O.或者等待获得内置锁而阻塞,那么中断请求只能设置线程的中断状态,除此之外没有其他任何作用。对于那些由于执行不可中断操作而被阻塞的线程,可以使用类似于中断的手段来停止这些线程,但这要求我们必须知道线程阻塞的原因。

Java. io 包中的同步Socket I/O。在服务器应用程序中,最常见的阻塞. I/O形式就是对套接字进行读取和写入。虽然InputStream和OutputStream中的read 和write 等方法都不会响应中断,但通过关闭底层的套接字,可以使得由于执行read 或write等方法而被阻塞的线程抛出一个SocketException。

Java. io包中的同步I/O。当中断一个正在InterruptibleChannel上等待的线程时,将抛出ClosedByInterruptException 并关闭链路(这还会使得其他在这条链路上阻塞的线程同样抛出ClosedByInterruptException)。当关闭一个InterruptibleChannel时,将导致所有在链路操作上阻塞的线程都抛出AsynchronousCloseException。大多数标准的Channel 都实现了InterruptibleChannel。

Selector 的异步I/O。如果一个线程在调用Selector. select 方法(在java. nio. channels中)时阻塞了,那么调用close 或wakeup 方法会使线程抛出ClosedSelectorException 并提前返回。

获取某个锁。如果一个线程由于等待某个内置锁而阻塞,那么将无法响应中断,因为线程认为它肯定会获得锁,所以将不会理会中断请求。但是,在Lock 类中提供了lockInterruptibly 方法,该方法允许在等待一个锁的同时仍能响应中断,请参见第13章。

程序清单7-11的ReaderThread 给出了如何封装非标准的取消操作。ReaderThread管理了一个套接字连接,它采用同步方式从该套接字中读取数据,并将接收到的数据传递给processBuffer。为了结束某个用户的连接或者关闭服务器,ReaderThread 改写了interrupt方法,使其既能处理标准的中断,也能关闭底层的套接字。因此,无论ReaderThread 线程是在read 方法中阻塞还是在某个可中断的阻塞方法中阻塞,都可以被中断并停止执行当前的工作。

public class ReaderThread extends Thread {

private final Socket socket;

private final InputStream in;

public ReaderThread(Socket socket) throws IOException {

this. socket =socket;

this. in =socket. get InputStream();

}

public void interrupt(){

try {

socket. close();

}

catch (IOException ignored){}

finally {

super. interrupt();

}

}

public void run().{

try {

byte[]buff=new byte[BUFSZ];

while (true){

int count =in. read(buff);

if  (count  < 0)

break;

else if (count >0)

processBuffer(buff, count);

}

}   catch    (IOException e)   {/*允许线程退出   */      }

}

}

                                                                      

 采用newTaskFor来封装非标准的取消

我们可以通过newTaskFor方法来进一步优化ReaderThread中封装非标准取消的技术,这

是Java 6在ThreadPoolExecutor中的新增功能。当把一个Callable 提交给ExecutorService时,submit 方法会返回一个Future,我们可以通过这个Future 来取消任务。newTaskFor是一个工厂方法,它将创建Future来代表任务。newTaskFor 还能返回一个RunnableFuture 接口,该接口扩展了Future和Runnable(并由FutureTask实现)。

通过定制表示任务的Future可以改变Future. cancel的行为。例如,定制的取消代码可以实现日志记录或者收集取消操作的统计信息,以及取消一些不响应中断的操作。通过改写interrupt方法,ReaderThread 可以取消基于套接字的线程。同样,通过改写任务的Future.cancel方法也可以实现类似的功能。

在程序清单7-12 的CancellableTask中定义了一个CancellableTask接口,该接口扩展了Callable,并增加了一个cancel 方法和一个newTask工厂方法来构造RunnableFuture。CancellingExecutor 扩展了ThreadPoolExecutor,并通过改写newTaskFor 使得CancellableTask可以创建自己的Future。

public interface CancellableTask<T>extends Callable<T>{

void cancel();

RunnableFuture<T>newTask();

}

@ThreadSafe

public class CancellingExecutor extends ThreadPoolExecutor {

...

protected<T>RunnableFuture<T>newTaskFor(Callable<T>callable){

if (callable instanceof CancellableTask)

return ((CancellableTask<T>) callable). newTask();

else

return super. newTaskFor(callable);

}

}

public abstract class SocketUsingTask<T>

implements CancellableTask<T>{

@GuardedBy("this") private socket socket;

protected synchronized void setSocket(Socket s){socket =s;}

public synchronized void cancel(){

try

if (socket !=null)

socket. close();

}catch (IOException ignored){}

}

public RunnableFuture<T>newTask(){

return new FutureTask<T>(this){

public boolean cancel(boolean mayInterruptIfRunning){

try {

SocketUsingTask. this. cancel();

}finally {。

return super. cancel(mayInterruptIfRunning);

1

SocketUsingTask实现了CancellableTask,并定义了Future. cancel来关闭套接字和调用super. cancel。如果SocketUsingTask 通过其自己的Future来取消,那么底层的套接字将被关闭并且线程将被中断。因此它提高了任务对取消操作的响应性:不仅能够在调用可中断方法的同时确保响应取消操作,而且还能调用可阻调的套接字I/O 方法。

相关文章:

线程任务的取消

如果外部代码能在某个操作正常完成之前将其置入“完成”状态&#xff0c;那么这个操作就可以称为可取消的(Cancellable)。取消某个操作的原因很多&#xff1a; 用户请求取消。用户点击图形界面程序中的“取消”按钮&#xff0c;或者通过管理接口来发出取消请求,例如JMX (Java …...

在线聊天项目

人事管理项目-在线聊天 后端接口实现前端实现 在线聊天是一个为了方便HR进行快速沟通提高工作效率而开发的功能&#xff0c;考虑到一个公司中的HR并不多&#xff0c;并发量不大&#xff0c;因此这里直接使用最基本的WebSocket来完成该功能。 后端接口实现 要使用WebSocket&…...

动态规划-硬币排成线

动态规划-硬币排成线 1 描述2 样例2.1 样例 1:2.2 样例 2:2.3 样例 3: 3 算法解题思路及实现3.1 算法解题分析3.1.1 确定状态3.1.2 转移方程3.1.3 初始条件和边界情况3.1.4 计算顺序 3.2 算法实现3.2.1 动态规划常规实现3.2.2 动态规划滚动数组 该题是lintcode的第394题&#x…...

有效的括号——力扣20

题目描述 思路 1.判断括号的有效性可以使用「栈」这一数据结构来解决 2.遍历给定的字符串 s。当遇到一个左括号时&#xff0c;我们会期望在后续的遍历中&#xff0c;有一个相同类型的右括号将其闭合。由于后遇到的左括号要先闭合&#xff0c;因此我们可以将这个左括号放入栈顶。…...

【轻量级网络】华为诺亚:VanillaNet

文章目录 0. 前言1. 网络结构2. VanillaNet非线性表达能力增强策略2.1 深度训练2.2 扩展激活函数 3. 总结4. 参考 0. 前言 随着人工智能芯片的发展&#xff0c;神经网络推理速度的瓶颈不再是FLOPs或参数量&#xff0c;因为现代GPU可以很容易地进行计算能力较强的并行计算。相比…...

读写ini配置文件(C++)

文章目录 1、为什么要使用ini或者其它(例如xml,json)配置文件&#xff1f;2、ini文件基本介绍3、ini配置文件的格式4、C读写ini配置文件5、 代码示例6、 配置文件的解析库 文章转载于&#xff1a;https://blog.csdn.net/weixin_44517656/article/details/109014236 1、为什么要…...

Python对接亚马逊电商平台SP-API的一些概念理解准备

❝ 除了第三方服务商&#xff0c;其实亚马逊卖家本身也可以通过和SP-API的对接&#xff0c;利用程序来自动化亚马逊店铺销售运营管理中很多环节的工作&#xff0c;简单的应用比如可以利用SP-API的对接&#xff0c;实现亚马逊卖家后台各类报表的定期自动下载以及数据分析整理工…...

[Halcon3D] 主流的3D光学视觉方案及原理

&#x1f4e2;博客主页&#xff1a;https://loewen.blog.csdn.net&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由 丶布布原创&#xff0c;首发于 CSDN&#xff0c;转载注明出处&#x1f649;&#x1f4e2;现…...

Go Web下gin框架使用(二)

〇、gin 路由 Gin是一个用于构建Web应用程序的Go语言框架&#xff0c;它具有简单、快速、灵活的特点。在Gin中&#xff0c;可以使用路由来定义URL和处理程序之间的映射关系。 r : gin.Default()// 访问 /index 这个路由// 获取信息r.GET("/index", func(c *gin.Con…...

算法笔记-线段树合并

线段树合并 前置知识&#xff1a;权值线段树、动态开点 将两棵线段树的信息合并成一棵线段树。 可以新建一颗线段树保存原来两颗线段树的信息&#xff0c;也可以将第二棵线段树维护的信息加到第一棵线段树上。 前者的空间复杂度较高&#xff0c;如果合并之前的线段树不会再用…...

Fiddler抓取IOS数据包实践教程

Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,设置断点,查看所有的“进出”Fiddler的数据(指cookie,html,js,css等文件)。 本章教程,主要介绍如何利用Fiddler抓取IOS数据包相关教程。 目录 一、打开Fiddler监听端口 二、配置网…...

Ansible基础4——变量、机密、事实

文章目录 一、变量二、机密2.1 创建加密文件2.2 查看加密文件2.3 编辑加密文件内容2.4 加密现有文件2.5 解密文件2.6 更改加密密码 三、事实3.1 收集展示事实3.2 展示某个结果3.3 新旧事实命令3.4 关闭事实3.5 魔法变量 一、变量 常设置的变量&#xff1a; 要创建的用户要安装的…...

React实现Vue的watch监听属性

在 Vue 中可以简单地使用 watch 来监听数据的变化&#xff0c;还能获取到改变前的旧值&#xff0c;而在 React 中是没有 watch 的。 React中比较复杂&#xff0c;但是我们如果想在 React 中实现一个类似 Vue 的 watch 监听属性&#xff0c;也不是没有办法。 在React类组件中实…...

axios、跨域与JSONP、防抖和节流

文章目录 一、axios1、什么是axios2、axios发起GET请求3、axios发起POST请求4、直接使用axios发起请求 二、跨域与JSONP1、了解同源策略和跨域2、JSONP&#xff08;1&#xff09;实现一个简单的JSONP&#xff08;2&#xff09;JSONP的缺点&#xff08;3&#xff09;jQuery中的J…...

macOS Ventura 13.5beta2 (22G5038d)发布

系统介绍 黑果魏叔 6 月 1 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 13.5 开发者预览版 Beta 2 更新&#xff08;内部版本号&#xff1a;22G5038d&#xff09;&#xff0c;本次更新距离上次发布隔了 12 天。 macOS Ventura 带来了台前调度、连续互通相机、Fac…...

jwt----介绍,原理

token&#xff1a;服务的生成的加密字符串&#xff0c;如果存在客户端浏览器上&#xff0c;就叫cookie -三部分&#xff1a;头&#xff0c;荷载&#xff0c;签名 -签发&#xff1a;登录成功&#xff0c;签发 -认证&#xff1a;认证类中认证 # jwt&…...

Three.js--》实现3d水晶小熊模型搭建

目录 项目搭建 初始化three.js基础代码 加载背景纹理 加载小熊模型 今天简单实现一个three.js的小Demo&#xff0c;加强自己对three知识的掌握与学习&#xff0c;只有在项目中才能灵活将所学知识运用起来&#xff0c;话不多说直接开始。 项目搭建 本案例还是借助框架书写…...

《阿里大数据之路》研读笔记(1)

首先先看到OLAP和OLTP的区别&#xff1a; OLTP(Online transaction processing):在线/联机事务处理。典型的OLTP类操作都比较简单&#xff0c;主要是对数据库中的数据进行增删改查&#xff0c;操作主体一般是产品的用户或者是操作人员。 OLAP(Online analytical processing):…...

Logback 日志框架详解

一、Logback 简介 Logback 是一个日志框架&#xff0c;旨在成为 log4j 的替代品。它由 Ceki Glc 创建并维护&#xff0c;是一款开源的日志框架&#xff0c;是 slf4j&#xff08;Simple Logging Facade for Java&#xff09;的实现。相比于 log4j&#xff0c;Logback 具有更高的…...

BIO、NIO、AIO 有什么区别?

BIO (Blocking I/O)&#xff1a; Block IO 同步阻塞式 IO &#xff0c;传统 IO&#xff0c;特点是模式简单、使用方便&#xff0c;并发处理能力低。 同步阻塞 I/O 模式&#xff0c;数据的读取写入必须阻塞在一个线程内等待其完成&#xff0c;在活动连接数不是特别高&#xff08…...

nginx和tomcat负载均衡、静态分离

tomcat重要目录 bin 存放启动和关闭Tomcat脚本conf存放Tomcat不同的配置文件doc存放Tomcat文档lib存放Tomcat运行需要的库文件logs存放Tomcat执行时的log文件src存放Tomcat的源代码webappsTomcat的主要Web发布目录work存放jsp编译后产生的class文件 nginx负载均衡原理 nginx实…...

用AI写出的高考作文!

今天是6月7日&#xff0c;又到了每一年高考的日子。小灰自己参加高考是在2004年&#xff0c;距离现在已经将近20年&#xff0c;现在回想起来&#xff0c;真的是恍如隔世。 今天高考语文的作文题是什么呢&#xff1f; 全国甲卷的题目是&#xff1a;人技术时间 人们因技术发展得以…...

chatgpt赋能python:Python屏幕输入介绍:了解命令行输入的基本知识

Python屏幕输入介绍&#xff1a;了解命令行输入的基本知识 Python是一种使用广泛的编程语言&#xff0c;用于编写各种类型的应用程序&#xff0c;包括图形用户界面应用程序和基于命令行的应用程序。对于基于命令行的应用程序来说&#xff0c;屏幕输入非常重要。本文将介绍Pyth…...

bert中文文本摘要代码(1)

bert中文文本摘要代码 写在最前面关于BERT使用transformers库进行微调 load_data.py自定义参数collate_fn函数BertDataset类主函数 tokenizer.py创建词汇表encode函数decode函数 写在最前面 熟悉bert&#xff0b;文本摘要的下游任务微调的代码&#xff0c;方便后续增加组件实现…...

为何溃坝事故频发,大坝安全如何保障?

随着水利水电工程的重要性日益突显&#xff0c;水库大坝安全越来越受到相关部门的重视。因为大坝的安全直接影响水利工程的功能与作用&#xff0c;因此对大坝安全的监测显得十分必要。大坝安全监测的作用是能够及时掌握大坝的运行状态&#xff0c;及时发现大坝的变形、渗漏等异…...

第十九章_手写Redis分布式锁

锁的种类 单机版同一个JVM虚拟机内synchronized或者Lock接口。 分布式多个不同JVM虚拟机&#xff0c;单机的线程锁机制不再起作用&#xff0c;资源类在不同的服务器之间共享了。 一个靠谱分布式锁需要具备的条件和刚需 独占性 &#xff1a;OnlyOne&#xff0c;任何时刻只能有且…...

电路设计【8】原理图中VCC、VDD、VEE、VSS、VBAT各表示什么意思

文章目录 一、名词解析二、应用讲解三、举例分析&#xff1a;为什么stm32vet6中要分出5对VDD VSS&#xff1f;它们分别负责哪些模块的供电&#xff1f; 一、名词解析 &#xff08;1&#xff09;VCC&#xff1a;Ccircuit 表示电路的意思, 即接入电路的电压 &#xff08;2&…...

Volatile、Synchronized、ReentrantLock锁机制使用说明

一、Volatile底层原理 volatile是轻量级的同步机制&#xff0c;volatile保证变量对所有线程的可见性&#xff0c;不保证原子性。 当对volatile变量进行写操作的时候&#xff0c;JVM会向处理器发送一条LOCK前缀的指令&#xff0c;将该变量所在缓存行的数据写回系统内存。由于缓…...

港联证券|AI概念股继续活跃 科创50指数逆势走高

周三&#xff0c;A股市场出现极致分化态势。得益于存储芯片为代表的硬科技股的强势&#xff0c;科创50指数逆势走高。但创业板指、深证成指等主要股指仍然跌跌不休&#xff0c;沪指险守3200点关口。AI概念股继续逆势活跃&#xff0c;国资云、数据方向领涨&#xff0c;算力概念股…...

分布式事务一 事物以及分布式事物介绍

一 事务简介 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。在关系数据库中&#xff0c;一个事务由一组SQL语句组成。事务应该具有4个属性&#xff1a;原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。 原子性&#xff08;at…...