并发编程之状态的依赖(一)
参考资料:
Doug Lea -------------<<java并发编程 设计原则与模式>>
场景 1 : 当一条线程的执行过程中的错误时来源于其他对象的临时错误或者这个错误是某个时间临时出现的,是可重试的.那么,当错误的时候, 可以稍微等待一段时间并使用轮询的方式重新尝试这个操作.
实例代码: 当远程连接服务器的时候,可能会接受到RimeOutException:
long delayTime = 5000 +(long)(Math.random()*5000);
for(;;){
//基于可恢复异常的轮询操作.
try{
//do your remote connection
}catch(TimeOutException e){
Thread.sleep(delayTime);//注意,sleep是含有锁的睡眠,可能在某些场景不合适.
delayTime = .....//重新定义一个更合适时间
}
}
注意: 上述的操作中,sleep操作可能在某种场景是不合适的:比如说这段代码是在某个高并发的时刻持有某个频繁会被请求的锁.那么,这个sleep会造成休眠时间内很多现成休眠.这个代价是比较大的.
上述的操作有一种要求,要求客户方会抛出相关的timeOutException.试想:
1 倘若接受不到这个异常
2 调用的方法根本不会抛出此异常
3 可能从线程的执行到抛出异常的时间比正常处理的时间还要多,不希望等到真正的超市抛出时候才处理.
这个时候, 自定义的超市实现可能会比较好,下面的代码来自互联网, 笔者觉得此方法是一种思路,所以将其中的部分代码截出, 感谢原作者提供思路:
<代码来自互联网>
public class TimeoutThread extends Thread{
/**
* 计时器超时时间
*/
private long timeout;
/**
* 计时是否被取消
*/
private boolean isCanceled = false;
/**
* 当计时器超时时抛出的异常
*/
private TimeoutException timeoutException;
/**
* 构造器
* @param timeout 指定超时的时间
*/
public TimeoutThread(long timeout,TimeoutException timeoutErr) {
super();
this.timeout = timeout;
this.timeoutException = timeoutErr;
//设置本线程为守护线程
this.setDaemon(true);
}
/**
* 取消计时
*/
public synchronized void cancel()
{
isCanceled = true;
}
/**
* 启动超时计时器
*/
public void run()
{
try {
Thread.sleep(timeout);
if(!isCanceled)
throw timeoutException;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
使用:
TimeoutThread t = new TimeoutThread(5000,new TimeoutException("超时"));
try{
t.start();
.....要检测超时的程序段....
t.cancel();
}catch (TimeoutException e)
{
...对超时的处理...
}
场景二: 子线程在执行的时候如果抛出异常, 希望把异常传递给一个专门负责处理异常的"异常处理器". 也可以传回给主线程来进行处理.
示例代码摘自《java 并发编程 设计原则与模式》
异常时候只通知一个线程
interface ServerWithException {
void service() throws ServiceException;
}
interface ServiceExceptionHandler {
void handle(ServiceException e);
}
class ServerImpl implements ServerWithException {
public void service() throws ServiceException {}
}
class HandlerImpl implements ServiceExceptionHandler {
public void handle(ServiceException e) {}
}
class HandledService implements ServerWithException {
final ServerWithException server = new ServerImpl();
final ServiceExceptionHandler handler = new HandlerImpl();
public void service() { // no throw clause
try {
server.service();
}
catch (ServiceException e) {
handler.handle(e);
}
}
}
下面是基于事件监听的方式方处理"异常通知合作伙伴"的方式:
class ExceptionEvent extends java.util.EventObject {
public final Throwable theException;
public ExceptionEvent(Object src, Throwable ex) {
super(src);
theException = ex;
}
}
class ExceptionEventListener { // Incomplete
public void exceptionOccured(ExceptionEvent ee) {
// ... respond to exception...
}
}
class ServiceIssuingExceptionEvent { // Incomplete
// ...
private final CopyOnWriteArrayList handlers =
new CopyOnWriteArrayList();
public void addHandler(ExceptionEventListener h) {
handlers.add(h);
}
public void service() {
// ...
boolean failed = true;
if (failed) {
Throwable ex = new ServiceException();
ExceptionEvent ee = new ExceptionEvent(this, ex);
for (Iterator it = handlers.iterator(); it.hasNext();) {
ExceptionEventListener l =
(ExceptionEventListener)(it.next());
l.exceptionOccured(ee);
}
}
}
}