`
victorzhzh
  • 浏览: 203015 次
  • 来自: ...
社区版块
存档分类
最新评论

阻塞方法引起的任务无法结束

阅读更多

做一个小练习记录一个阻塞方法引起的任务无法结束。

场景如下:一个生成质素的类,多个线程调用这个类生成一系列质素。

质素生成类:

public class PrimeGeneratorForeverRun implements
		Callable<BlockingQueue<BigInteger>> {
	private final BlockingQueue<BigInteger> primes = new ArrayBlockingQueue<BigInteger>(
			5);//使用阻塞队列来存储已经生成的质素
	private volatile boolean cancelled = false;//退出条件
	private static BigInteger b = BigInteger.ONE;

	@Override
	public BlockingQueue<BigInteger> call() throws Exception {
		System.out.println("Begin Time: " + new Date());
		while (!cancelled) {
			TimeUnit.SECONDS.sleep(1);
			synchronized (this) {
				b = b.nextProbablePrime();
				primes.put(b);
			}
		}
		System.out.println("End Time: " + new Date());
		return primes;
	}

	public void cancel() {//当外部调用这个方法时,将时call中的while循环退出
		cancelled = true;
	}
}

 测试类:

public class PrimeGeneratorForeverRunTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		PrimeGeneratorForeverRun primeGenerator = new PrimeGeneratorForeverRun();//定义一个单例的质素生成器
		ExecutorService service = Executors.newFixedThreadPool(2);//定义线程池的大小为2
		Future<BlockingQueue<BigInteger>> result1 = service.submit(primeGenerator);//提交任务
		Future<BlockingQueue<BigInteger>> result2 = service.submit(primeGenerator);
		try {
			TimeUnit.SECONDS.sleep(10);//守护线程沉睡10秒,目的是向在10秒内让任务1,2不停的生成质素
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			primeGenerator.cancel();//停止生成质素
			service.shutdown();//关闭线程池,这里使用平滑关闭,目的是不强制退出任何线程
			try {
				BlockingQueue<BigInteger> list = result1.get();//获取第一个任务生成的所有质素
				for (BigInteger bigInteger : list) {
					System.out.print(bigInteger + ",");
				}
				System.out.println();
				list = result2.get();
				for (BigInteger bigInteger : list) {//获取第二个任务生成的所有质素
					System.out.print(bigInteger + ",");
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
	}

}

 运行测试类,程序死掉了,一直在运行,查看JVM线程栈信息:

Full thread dump Java HotSpot(TM) Server VM (17.0-b16 mixed mode):

"Attach Listener" daemon prio=10 tid=0x08e7ec00 nid=0x4392 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"pool-1-thread-2" prio=10 tid=0x08e70400 nid=0x4369 waiting on condition [0x7b629000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0xa285ddf0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
	at java.util.concurrent.ArrayBlockingQueue.put(ArrayBlockingQueue.java:252)
	at org.victorzhzh.concurrency.PrimeGeneratorForeverRun.call(PrimeGeneratorForeverRun.java:24)
	- locked <0xa285db78> (a org.victorzhzh.concurrency.PrimeGeneratorForeverRun)
	at org.victorzhzh.concurrency.PrimeGeneratorForeverRun.call(PrimeGeneratorForeverRun.java:1)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:619)

   Locked ownable synchronizers:
	- <0xa285e710> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"pool-1-thread-1" prio=10 tid=0x08e6cc00 nid=0x4368 waiting for monitor entry [0x7b87a000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.victorzhzh.concurrency.PrimeGeneratorForeverRun.call(PrimeGeneratorForeverRun.java:23)
	- waiting to lock <0xa285db78> (a org.victorzhzh.concurrency.PrimeGeneratorForeverRun)
	at org.victorzhzh.concurrency.PrimeGeneratorForeverRun.call(PrimeGeneratorForeverRun.java:1)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:619)

   Locked ownable synchronizers:
	- <0xa285e520> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"Low Memory Detector" daemon prio=10 tid=0x08e57400 nid=0x4366 runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"CompilerThread1" daemon prio=10 tid=0x08e54000 nid=0x4365 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"CompilerThread0" daemon prio=10 tid=0x08e52000 nid=0x4364 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"Signal Dispatcher" daemon prio=10 tid=0x08e50400 nid=0x4363 runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"Finalizer" daemon prio=10 tid=0x08e3dc00 nid=0x4362 in Object.wait() [0x7be83000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0xa2820b10> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118)
	- locked <0xa2820b10> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134)
	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)

   Locked ownable synchronizers:
	- None

"Reference Handler" daemon prio=10 tid=0x08e3c400 nid=0x4361 in Object.wait() [0x7bed4000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0xa2820a18> (a java.lang.ref.Reference$Lock)
	at java.lang.Object.wait(Object.java:485)
	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
	- locked <0xa2820a18> (a java.lang.ref.Reference$Lock)

   Locked ownable synchronizers:
	- None

"main" prio=10 tid=0x08db0400 nid=0x435d waiting on condition [0xb6b1a000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0xa285e4c0> (a java.util.concurrent.FutureTask$Sync)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:969)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1281)
	at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:218)
	at java.util.concurrent.FutureTask.get(FutureTask.java:83)
	at org.victorzhzh.concurrency.PrimeGeneratorForeverRunTest.main(PrimeGeneratorForeverRunTest.java:30)

   Locked ownable synchronizers:
	- None

"VM Thread" prio=10 tid=0x08e39800 nid=0x4360 runnable 

"GC task thread#0 (ParallelGC)" prio=10 tid=0x08db7800 nid=0x435e runnable 

"GC task thread#1 (ParallelGC)" prio=10 tid=0x08db9000 nid=0x435f runnable 

"VM Periodic Task Thread" prio=10 tid=0x08e59000 nid=0x4367 waiting on condition 

JNI global references: 855

 主要看,如下信息:

"pool-1-thread-2" prio=10 tid=0x08e70400 nid=0x4369 waiting on condition [0x7b629000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0xa285ddf0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
	at java.util.concurrent.ArrayBlockingQueue.put(ArrayBlockingQueue.java:252)
	at org.victorzhzh.concurrency.PrimeGeneratorForeverRun.call(PrimeGeneratorForeverRun.java:24)
	- locked <0xa285db78> (a org.victorzhzh.concurrency.PrimeGeneratorForeverRun)
	at org.victorzhzh.concurrency.PrimeGeneratorForeverRun.call(PrimeGeneratorForeverRun.java:1)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:619)

   Locked ownable synchronizers:
	- <0xa285e710> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"pool-1-thread-1" prio=10 tid=0x08e6cc00 nid=0x4368 waiting for monitor entry [0x7b87a000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.victorzhzh.concurrency.PrimeGeneratorForeverRun.call(PrimeGeneratorForeverRun.java:23)
	- waiting to lock <0xa285db78> (a org.victorzhzh.concurrency.PrimeGeneratorForeverRun)
	at org.victorzhzh.concurrency.PrimeGeneratorForeverRun.call(PrimeGeneratorForeverRun.java:1)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:619)

   Locked ownable synchronizers:
	- <0xa285e520> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

 由于阻塞队列满了,所以pool-1-thread-2进入了等待状态,而由于pool-1-thread-2锁住了PrimeGeneratorForeverRun对象,所以pool-1-thread-1进入了阻塞状态,因此即使这时我们调用了PrimeGeneratorForeverRun.cancel()方法,也无法停止生成质素的循环,因为线程一个处于等待状态,一个处于阻塞状态,都不能取校验cancelled标志位,所以线程只能保持源状态继续,而守护线程中我们用的是shutdown,只要有线程在运行那么线程池就不会关闭,因此程序将一直运行。

解决方法很容易了,这里就不再列出。

分享到:
评论
7 楼 cangchen8180 2016-10-21  
这个问题怎么解决的啊,能不能分享一下???[b][/b]
6 楼 lshxy320 2014-05-27  
解决方法很容易???怎么解决的啊?
5 楼 pjfox163 2013-06-28  
primes.put(b);
这里try一下就可以了,原因是阻塞队列最大是5,当第六个值往里放得时候抛异常了。所有一直没有返回primes这个队列,所有一直等待。
或者改成primes.offer(b)这个直接返回boolean型不会抛异常。
4 楼 luoaz 2012-09-03  
楼主,这个问题怎么解决的啊,能不能分享一下,我们现在遇到了这个问题,但不知道怎么解决
3 楼 azhu1123 2012-02-13  
真心求解决办法说明……自己有尝试集中方式,都没有解决。谢谢
2 楼 agapple 2011-05-06  
看走眼,原来你只是使用了一个boolean标志位。
1 楼 agapple 2011-05-06  
cancel的支持,无非是通过Thread.intrupte,需要对应的runnable支持,这在我们目前很多开发编程中缺少这样的意识。

可以换另一种思路,runnable线程实现一个可cancel的操作,每次异步线程进行Thread.intrupte操作时,通过Thread特定的钩子主动调用runnable的cancel方法。

相关推荐

    FreeRTos学习笔记

    在FreeRTOS中,中断处理程序也可能会引起任务的调度。为了保证任务切换的安全性,FreeRTOS提供了一种机制来保证在中断上下文中对任务的操作是安全的。 **1. 关闭中断** 在进行关键操作时,可以使用`taskENTER_...

    PHP中Session引起的脚本阻塞问题解决办法

    该函数的作用是写入当前Session数据并结束Session,释放对Session文件的锁定。这样,即使在长时间运行的脚本中,也能及时解锁,允许其他请求继续执行。 案例一中提到,当一个PHP程序在处理页面时,如果涉及到...

    android多种定时器实现

    使用`Timer` 需要创建一个`Timer` 实例,并通过`schedule()` 或者`scheduleAtFixedRate()` 方法来安排任务。`TimerTask` 是一个抽象类,你需要创建它的子类并重写`run()` 方法来定义需要执行的任务。例如: ```...

    多线程&&多进程.pdf

    对于IO密集型任务(如网络请求、文件读写等),使用多线程可以有效提高程序的执行效率,因为IO操作通常会引起线程挂起,此时其他线程可以利用这段时间执行。但对于计算密集型任务,GIL会成为瓶颈,导致多线程无法...

    NSIS拖曳防卡死方法

    - **异步处理**:确保长时间运行的任务(如注册组件、创建快捷方式等)在后台线程中执行,避免阻塞主线程。这样即使用户进行拖曳操作,也不会影响主线程的消息处理。 - **消息泵**:在长时间运行的任务中,添加消息...

    Java软件开发实战 Java基础与案例开发详解10-6 getMessage和printStackTrace方法共6页.pdf

    - **方法**:`start()`用于启动线程,`join()`用于等待线程结束,`isAlive()`用于检查线程是否还活着。 #### 12.3 线程的调度和优先级 - **调度**:操作系统负责线程的调度。 - **优先级**:线程可以根据优先级...

    java多线程笔记

    值得注意的是,`stop()`方法已弃用,因为可能引起数据不一致,推荐使用`interrupt()`。 守护线程(Daemon Thread)是一种特殊的线程,当所有非守护线程结束后,即使还有守护线程在运行,JVM也会退出。`setDaemon...

    Java 并发编程硬核资料.pdf

    3. 正确停止线程的方法主要包括使用interrupt()方法中断线程以及设置一个退出条件来控制线程结束。 4. Java线程有六种状态:新建、就绪、运行、阻塞、等待、超时等待和终止。线程状态间的切换由Java虚拟机和操作系统...

    因散热导致笔记本电脑运行速度慢的解决方法.docx

    2. **出风口**:出风口是热气逸出的通道,如果出风口被灰尘堵塞,热空气无法有效地排出,热量会积累在电脑内部,从而降低性能。用户可以尝试用棉球或其他软性材料清理出风口,如果条件允许,拆下散热模块进行深度...

    计算机系统结构三四章作业及答案.pdf

    5. **启动与清空时间**:流水线在开始运行和结束时,需要一定时间进行初始化和清空,这段时间内无法满负荷工作,影响总体效率。 解决流水线瓶颈问题通常有两种方法: - **细分瓶颈段**:将瓶颈段进一步细分成更小...

    time_over_check_.rar_Over

    2. 异步处理:利用多线程或异步编程模型,确保数据接收不会阻塞其他重要任务。 3. 优化算法:如果时间溢出是由于算法效率低引起的,可以查看这两个文件中是否提供了改进算法的建议。 4. 流量控制:在接收数据时,...

    端口扫描实验报告(不是很长)

    - 非阻塞I/O:通过非阻塞I/O,程序可以在等待连接响应的同时处理其他任务,减少了等待时间,提高了整体性能。 - 主要逻辑: - `StartScan`线程:负责启动`DoScanPort`线程,根据用户指定的端口范围或单个端口...

    Android性能优化典范 - 第5季 - 胡凯1

    为了避免掉帧问题,我们需要使用多线程技术方案,把那些操作复杂的任务移动到其他线程中执行,这样就不容易阻塞主线程的操作,也就减少了出现掉帧的可能性。 Android系统为我们提供了若干组件类来帮助解决这个...

    java 多线程.ppt,多线程

    如果在同步块或方法中调用sleep(),不会引起死锁。 8. 异常处理: 在多线程环境中,每个线程都有自己的异常处理栈。如果在某个线程中抛出未捕获的异常,该线程会终止,但不影响其他线程。 9. 死锁: 死锁是两个...

    中央空调水处理常见问题及处理方法.pdf

    它们产生的氧气加速腐蚀,同时与泥浆或CaCO3结合,引起设备堵塞或结垢,降低传热效率。 4. 悬浮物 冷冻水系统中的悬浮物相对较少,因为系统封闭,不需补充水,且不接触空气。 处理方法: 1. 清洗 清洗过程中,...

    java 面试宝典

    - **同步**:当前线程等待操作完成,阻塞状态直到操作结束。 - **异步**:当前线程提交任务后继续执行,由另一个线程或线程池来完成任务。 例如,文件读取可以同步执行,而网络请求通常采用异步方式。 **49. 下面...

    BackgroundWorker初始化进度条

    - `RunWorkerCompleted`事件在后台任务结束时触发,可以在这里处理任务完成后的逻辑,例如关闭进度条或者显示结果。 5. **启动后台任务** - 调用`BackgroundWorker`的`RunWorkerAsync`方法开始执行任务。在此之后...

    visual basic.net 线程参考手册

    线程有主要(主线程)和次要(工作线程)之分,主线程通常是程序的入口点,而工作线程用于执行非UI相关的任务,避免阻塞用户界面。 二、线程同步与互斥 为了确保线程安全,VB.NET提供了多种同步机制。Monitor类提供...

    java面试题(线程和JSP及EJB部分).pdf

    - `suspend()`方法:容易引起死锁,因为线程虽然暂停,但仍然持有锁。应该使用`wait()`方法让线程进入等待状态,等待其他线程通知。 4. **`sleep()`与`wait()`的区别**: - `sleep()`:使当前线程暂停指定时间,...

Global site tag (gtag.js) - Google Analytics