技术开发 频道

JAVA线程:如何解决资源共享冲突(上)

  要想使线程成为后台线程,必须则在线程启动前调用setDaemon()方法,才能把这个线程设置为后台线程。当我们运行这个程序时候,发现没有任何结果打印到控制台,这就是因为没有非后台线程(除了main,main是一个非后台线程)使得程序保持运行。因此,程序没有打印任何信息就停止了。

  好了,现在回到我们讲到的第一个实例代码,我想根据这个代码改写下,写一个测试框架,这个框架可以简化对我们遇到这种类型线程例子的测试工作。我们的watcher线程实际上是观察特定情况下监控对象内部是否违反了约束条件,对于客户而言,客户指向知道我们定义的约束条件是否被违反了,还要知道这个违反约束条件的数值是多少,如是我定义了下面的接口:

package cn.com.sxia;
public interface InvariantState {}

   这接口就是为了查看数值是否违反我们定义约束的接口,它有两个实现类:

  表示成功的:

package cn.com.sxia;
public class InvariantOK implements InvariantState {    }

   表示失败的:

package cn.com.sxia;
public class InvariantFailure implements InvariantState {
    public Object value;    
    public InvariantFailure(Object value)
    {
        this.value = value;
    }
}

   在InvariantFailure对象将包括一个对象,这个对象表示了有关失败原因的信息,当监控到失败情况我们就可以打印出有关失败的错误信息。

  下面我们再定义一个接口,任何需要对我们定义的约束条件进行测试的类都必须要实现这个接口:

package cn.com.sxia;
public interface Invariant {
    InvariantState invariant();
}

  为了防止程序因为所运行的平台(例如不同版本的windows,linux,多核系统等)对java底层技术支持的问题我们再定义一个超时类,这个类当程序在一定时间内无法正常运行时候,程序会自动终止,代码如下:

package cn.com.sxia;

import java.util.Timer;
import java.util.TimerTask;

public class Timeout extends Timer {
public Timeout(int delay,final String msg){
super(true);//设为true表明该线程是一个后台线程(Daemon)
schedule(new TimerTask() {
@Override
public void run() {
System.out.println(msg);
System.exit(0);
}
}, delay);
}

}

  代码里我们继承了Timer类,在构造函数里我们调用了super(true),这个设置表明此线程将作为一个后台程序创建,前面我们讲到后台线程不会影响到非后台程序,也就是说当其他线程让程序退出时候,这个创建的Timeout对象不会干扰其他线程的运行。Timer类非常有用,java里设计它就是为了处理大量并发调度任务,下面是Timer在jdk文档里的解释:

    public class Timer extends Object
        一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。
        与每个 Timer 对象相对应的是单个后台线程,用于顺序地执行所有计时器任务。计时器任务应该迅速完成。如果完成某个计时器任务的时间太长,那么它会“独占”计时器的任务执行线程。因此,这就可能延迟后续任务的执行,而这些任务就可能“堆在一起”,并且在上述不友好的任务最终完成时才能够被快速连续地执行。
        对 Timer 对象最后的引用完成后,并且 所有未处理的任务都已执行完成后,计时器的任务执行线程会正常终止(并且成为垃圾回收的对象)。但是这可能要很长时间后才发生。默认情况下,任务执行线程并不作为守护线程 来运行,所以它能够阻止应用程序终止。如果调用者想要快速终止计时器的任务执行线程,那么调用者应该调用计时器的 cancel 方法。
        如果意外终止了计时器的任务执行线程,例如调用了它的 stop 方法,那么所有以后对该计时器安排任务的尝试都将导致 IllegalStateException,就好像调用了计时器的 cancel 方法一样。
        此类是线程安全的:多个线程可以共享单个 Timer 对象而无需进行外部同步。
        此类不 提供实时保证:它使用 Object.wait(long) 方法来安排任务。
        实现注意事项:此类可扩展到大量同时安排的任务(存在数千个都没有问题)。在内部,它使用二进制堆来表示其任务队列,所以安排任务的开销是 O(log n),其中 n 是同时安排的任务数。
        实现注意事项:所有构造方法都启动计时器线程。

 

0
相关文章