概念上的 MVC 形式被描述为多个目的 ——,并且会介绍其首要API的施用办法

       本文首要分为四个部分,第二片段首先会对ScheduledThreadPoolExecutor实行简短的牵线,并且会介绍其主要性API的利用办法,然后介绍了其选择时的注意点,第壹有个别则重要对ScheduledThreadPoolExecutor的完毕细节实行介绍。

   
Model-View-Controller(模型-视图-调控器,MVC)格局将您的软件组织并分解成多少个完全分化的角色:

那是二个silverlight游戏:http://keleyi.com/keleyi/phtml/silverlight/

1. 应用简介

       ScheduledThreadPoolExecutor是一个使用线程池试行定期职责的类,相较于Java中提供的另二个施行定期任务的类Timer,其关键有如下多个亮点:

  • 动用三十二线程施行职责,不用操心职责推行时间过长而导致职分互相阻塞的状态,Timer是单线程试行的,由此会出现那几个标题;
  • 永不操心任务实践进度中,即便线程失活,其会新建线程推行职责,提姆er类的单线程挂掉之后是不会重复成立线程实践后续职责的。

       除去上述多少个亮点外,ScheduledThreadPoolExecutor还提供了非常灵活的API,用于实践任务。其职务的进行攻略首要分为两大类:1在必然延迟之后只实行一回有个别义务;二在自然延迟之大顺期性的实行有个别职责。如下是其首要API:

public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                 long initialDelay, long delay, TimeUnit unit);
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay, long period, TimeUnit unit);

       上述多个主意中,第叁个和首个主意属于第二类,即在delay钦定的延期之后实行第1个参数所钦点的任务,分歧在于,第二个艺术实行之后会有再次来到值,而首先个方式施行之后是未曾再次回到值的。第几个和第5个方法则属于第一类,即在其次个参数(initialDelay)钦点的年华过后起初周期性的进行职分,实行周时期隔为第5个参数钦点的年月,然则这三个主意的分别在于第伍个主意实施职务的区间是定位的,无论上二个职务是不是试行到位,而第多少个措施的推行时间间隔是不稳固的,其会在周期任务的上二个职务执行到位之后才起来计时,并在钦赐时期距离之后才早先实行职责。如下是利用scheduleWithFixedDelay()和scheduleAtFixedRate()方法编写的测试用例:

public class ScheduledThreadPoolExecutorTest {
  private ScheduledThreadPoolExecutor executor;
  private Runnable task;

  @Before
  public void before() {
    executor = initExecutor();
    task = initTask();
  }

  private ScheduledThreadPoolExecutor initExecutor() {
    return new ScheduledThreadPoolExecutor(2);;
  }

  private Runnable initTask() {
    long start = System.currentTimeMillis();
    return () -> {
      print("start task: " + getPeriod(start, System.currentTimeMillis()));
      sleep(SECONDS, 10);
      print("end task: " + getPeriod(start, System.currentTimeMillis()));
    };
  }

  @Test
  public void testFixedTask() {
    print("start main thread");
    executor.scheduleAtFixedRate(task, 15, 30, SECONDS);
    sleep(SECONDS, 120);
    print("end main thread");
  }

  @Test
  public void testDelayedTask() {
    print("start main thread");
    executor.scheduleWithFixedDelay(task, 15, 30, SECONDS);
    sleep(SECONDS, 120);
    print("end main thread");
  }

  private void sleep(TimeUnit unit, long time) {
    try {
      unit.sleep(time);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  private int getPeriod(long start, long end) {
    return (int)(end - start) / 1000;
  }

  private void print(String msg) {
    System.out.println(msg);
  }
}

       能够看来,上述多个测试用例代码块基本是同样的,区别在于第2个用例调用的是scheduleAtFixedRate()方法,而第三个用例调用的是scheduleWithFixedDelay()。这里多个用例都以安装的在延迟一5s后各种30s实践贰次内定的天职,而该职务执行时间长度为十s。如下分别是那多少个测试用例的实践结果:

start main thread
start task: 15
end task: 25
start task: 45
end task: 55
start task: 75
end task: 85
start task: 105
end task: 115
end main thread

start main thread
start task: 15
end task: 25
start task: 55
end task: 65
start task: 95
end task: 105
end main thread

      相比上述推行结果能够看来,对于scheduleAtFixedRate()方法,其每一遍推行职分的开始时间间隔都为一定不改变的30s,与职务奉行时间长度非亲非故,而对此scheduleWithFixedDelay()方法,其每一遍施行职责的起来时间距离都为上次职分实施时间累加钦定的时间间隔。

       这里关于ScheduledThreadPoolExecutor的运用有3点须要验证如下:

  • ScheduledThreadPoolExecutor继承自ThreadPoolExecutor(ThreadPoolExecutor详解),由此也会有持续而来的execute()和submit()方法,不过ScheduledThreadPoolExecutor重写了这多个主意,重写的方法是直接创立多少个立时实践并且只进行二回的任务;
  • ScheduledThreadPoolExecutor使用ScheduledFutureTask封装每一种须求举办的任务,而任务都以放入DelayedWorkQueue队列中的,该队列是三个采用数组完成的先行队列,在调用ScheduledFutureTask::cancel()方法时,其会依据removeOnCancel变量的装置来确认是或不是须求将当前职责真正的从队列中移除,而不只是标志其为已去除状态;
  • ScheduledThreadPoolExecutor提供了一个钩子方法decorateTask(Runnable,
    RunnableScheduledFuture)用于对实践的天职进行装点,该办法第多个参数是调用方传入的职务实例,首个参数则是行使ScheduledFutureTask对用户传入任务实例举行打包之后的实例。这里须要注意的是,在ScheduledFutureTask对象中有1个heapIndex变量,该变量用于记录当前实例处于队列数组中的下标地方,该变量能够将诸如contains(),remove()等方法的年华复杂度从O(N)下跌到O(logN),由此成效升高是相比高的,不过固然这里用户重写decorateTask()方法封装了队列中的职责实例,那么heapIndex的优化就不设有了,因此这里刚毅提议是尽可能不要重写该方法,只怕重写时也照旧复用ScheduledFutureTask类。
  • Model
    封装了你的选择数据、应用流程和业务逻辑。
  • View
    从 Model 获取数据并格式化数据以拓展显示。
  • Controller
    调控造进程序流程,接收输入,并把它们传递给 Model 和 View。

接了个单子,非要用Silverlight
五来作二个品类,以前平素没接触过那东西,为了专门的职业,硬着头皮也要上了。探究了1夜晚,大至整理出部分门类中要求的东西,以下作为初探记录:

二. 源码详解

   
与其余设计形式差异,MVC
情势并不曾一向反映三个您可见编写或安插的类协会。相反,MVC
更像叁个定义上的指引标准或范型。概念上的 MVC 格局被描述为八个对象 ——
Model、View 和 Controller —— 之间的涉嫌。由于 View 和 Controller
都得以从 Model 请求数据,所以 Controller 和 View 都注重Model。任何输入都由此 Controller 进入你的系统,然后 Controller 选取一个View 来产生结果。

Silverlight 伍与Javascript的交谈格局

贰.1 首要质量

       ScheduledThreadPoolExecutor主要有八个属性,分别如下:

private volatile boolean continueExistingPeriodicTasksAfterShutdown;

private volatile boolean executeExistingDelayedTasksAfterShutdown = true;

private volatile boolean removeOnCancel = false;

private static final AtomicLong sequencer = new AtomicLong();
  • continueExistingPeriodicTasksAfterShutdown:用于标志当前Executor对象shutdown时,是还是不是继续实践已经存在于职务队列中的定期职务(调用scheduleAtFixedRate()方法生成的任务);
  • executeExistingDelayedTasksAfterShutdown:用于标志当前Executor对象shutdown时,是或不是继续试行已经存在于职务队列中的定期职务(调用scheduleWithFixedDelay()方法生成的义务);
  • removeOnCancel:用于标记假若当前职务已经撤销了,是不是将其从职责队列中确确实实的移除,而不只是标识其为除去状态;
  • 公海赌船网站,sequencer:其为一个AtomicLong类型的变量,该变量记录了当前任务被成立时是第多少个任务的四个序号,这些序号的严重性用来确认当七个义务起先实行时间同有时具体哪些职责先实践,比方八个职分的起来实践时间都为1515847881158,那么序号小的天职将先推行。

    Model
包罗了您的应用逻辑和数目,在您的应用程序中,它很可能是首要的值驱动器。Model
未有其它与表现层相关的特征,而且也和 HTTP
请求管理职分中完全非亲非故。

Silverlight
五属于客户端的事物,客户端的东西与劳动器端沟通,第有时常间想到了基于javascript的ajax那一个万能胶,所以先从Silverlight
伍与Javascript交互形式出手。

2.2 ScheduledFutureTask

       在ScheduledThreadPoolExecutor中,首要选择ScheduledFutureTask封装必要进行的职务,该类的主要注脚如下:

private class ScheduledFutureTask<V> extends FutureTask<V> implements RunnableScheduledFuture<V> {

  private final long sequenceNumber;    // 记录当前实例的序列号
  private long time;    // 记录当前任务下次开始执行的时间

  // 记录当前任务执行时间间隔,等于0则表示当前任务只执行一次,大于0表示当前任务为fixedRate类型的任务,
  // 小于0则表示其为fixedDelay类型的任务
  private final long period;

  RunnableScheduledFuture<V> outerTask = this;  // 记录需要周期性执行的任务的实例
  int heapIndex;    // 记录当前任务在队列数组中位置的下标

  ScheduledFutureTask(Runnable r, V result, long ns, long period) {
    super(r, result);
    this.time = ns;
    this.period = period;
    this.sequenceNumber = sequencer.getAndIncrement();  // 序号在创建任务实例时指定,且后续不会变化
  }

  public long getDelay(TimeUnit unit) {
    return unit.convert(time - now(), NANOSECONDS);
  }

  // 各个任务在队列中的存储方式是一个基于时间和序号进行比较的优先队列,当前方法定义了优先队列中两个
  // 任务执行的先后顺序。这里先对两个任务开始执行时间进行比较,时间较小者优先执行,若开始时间相同,
  // 则比较两个任务的序号,序号小的任务先执行
  public int compareTo(Delayed other) {
    if (other == this)
      return 0;
    if (other instanceof ScheduledFutureTask) {
      ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
      long diff = time - x.time;
      if (diff < 0)
        return -1;
      else if (diff > 0)
        return 1;
      else if (sequenceNumber < x.sequenceNumber)
        return -1;
      else
        return 1;
    }
    long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
    return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
  }

  public boolean isPeriodic() { // 判断是否为周期性任务
    return period != 0;
  }

  // 当前任务执行之后,会判断当前任务是否为周期性任务,如果为周期性任务,那么就调用当前方法计算
  // 当前任务下次开始执行的时间。这里如果当前任务是fixedRate类型的任务(p > 0),那么下次执行时间
  // 就是此次执行的开始时间加上时间间隔,如果当前任务是fixedDelay类型的任务(p < 0),那么下次执行
  // 时间就是当前时间(triggerTime()方法会获取系统当前时间)加上任务执行时间间隔。可以看到,定频率
  // 和定延迟的任务的执行时间区别就在当前方法中进行了指定,因为调用当前方法时任务已经执行完成了,
  // 因而triggerTime()方法中获取的时间就是任务执行完成之后的时间点
  private void setNextRunTime() {
    long p = period;
    if (p > 0)
      time += p;
    else
      time = triggerTime(-p);
  }

  // 取消当前任务的执行,super.cancel(boolean)方法也即FutureTask.cancel(boolean)方法。该方法传入
  // true表示如果当前任务正在执行,那么立即终止其执行;传入false表示如果当前方法正在执行,那么等待其
  // 执行完成之后再取消当前任务。
  public boolean cancel(boolean mayInterruptIfRunning) {
    boolean cancelled = super.cancel(mayInterruptIfRunning);
    // 判断是否设置了取消后移除队列中当前任务,是则移除当前任务
    if (cancelled && removeOnCancel && heapIndex >= 0)  
      remove(this);
    return cancelled;
  }

  public void run() {
    boolean periodic = isPeriodic();    // 判断是否为周期性任务
    if (!canRunInCurrentRunState(periodic)) // 判断是否能够在当前状态下执行该任务
      cancel(false);
    else if (!periodic) // 如果能执行当前任务,但是任务不是周期性的,那么就立即执行该任务一次
      ScheduledFutureTask.super.run();
    else if (ScheduledFutureTask.super.runAndReset()) { // 是周期性任务,则立即执行当前任务并且重置
      setNextRunTime(); // 在当前任务执行完成后调用该方法计算当前任务下次执行的时间
      reExecutePeriodic(outerTask); // 将当前任务放入任务队列中以便下次执行
    }
  }
}

       在ScheduledFutureTask中,首要有八个点必要强调:

  • 对于run()方法的首先个分支,canRunInCurrentRunState()方法的扬言如下所示,可以见到,该措施是用以判定当前任务假诺为周期性职责,那么其是或不是同意在shutdown状态下继续试行已经存在的周期性职责,是则代表近些日子情景下是足以施行当前任务的,这里isRunningOrShutdown()方法承袭自ThreadPoolExecutor;

    boolean canRunInCurrentRunState(boolean periodic) {
    return isRunningOrShutdown(periodic ?

                             continueExistingPeriodicTasksAfterShutdown :
                             executeExistingDelayedTasksAfterShutdown);
    

    }

  • 在run()方法的末尾1个if分支中,其首先会举办业前义务,在施行到位时才会调用setNextRunTime()方法设置后一次职务实践时间,也正是说对于fixedRate和fixedDelay类型的天职都是在那个小时点才设置的,因此纵然fixedRate类型的职务,尽管该职务下一次施行时间比当下光阴要早,其也只会在当前职务试行到位后旋即推行,而不会与当前任务还未实施完时就实行;对于fixedDelay职责则不会存在该难点,因为其是以职分成功后的年月点为底蕴测算后一次推行的时间点;

  • 对于run()方法的末尾多少个支行中的reExecutePeriodic()方法,其会将当前职务加入到职责队列中,并且调用父类的ensurePrestart()方法确认保障有可用的线程来施行当前职责,如下是该格局的实际落成:

    void reExecutePeriodic(RunnableScheduledFuture task) {
    if (canRunInCurrentRunState(true)) { // 判别当前职责是还是不是足以继续试行

    super.getQueue().add(task); // 将当前任务加入到任务队列中
    if (!canRunInCurrentRunState(true) && remove(task)) // 双检查法判断任务在加入过程中是否取消了
      task.cancel(false);
    else
      ensurePrestart(); // 初始化核心线程等确保任务可以被执行
    

    }
    }

       从ScheduledFutureTask的落到实处总计来看,当每创制叁个此类实例时,会伊始化该类的有个别根性情能,如下一次上马实践的时间和实施的周期。当有些线程调用该义务,即试行该职责的run()方法时,假如该义务不为周期性职务,那么实施该任务之后就不会有此外的动作,倘若该职分为周期性职责,那么在将当前职责执行完成之后,还有大概会重新载入参数当前职务的景况,并且总括下一次实践当前任务的小运,然后将其放入队列中以便后一次实践。

    Domain
Model
是三个目的层,是对实际世界逻辑、数据和您应用程序所管理的难题的架空。

一、Silverlight 5发言,Javascript倾听

2.3 DelayedWorkQueue

       DelayedWorkQueue的落实与DelayQueue以及PriorityQueue的完毕基本相似,格局都为3个预先队列,并且底层是行使堆结构来兑现优先队列的效应,在数额存款和储蓄方式上,其使用的是数组来促成。这里DelayedWorkQueue与DelayQueue以及PriorityQueue差异的点在于DelayedWorkQueue中根本囤积ScheduledFutureTask类型的职分,该职务中有1个heapIndex属性保存了当前任务在日前队列数组中的地方下标,其首要进步的是对队列的诸如contains()和remove()等要求牢固当前任务地方的不2秘诀的功效,时间复杂度能够从O(N)进步到O(logN)。如下是DelayedWorkQueue的落实代码(这里只列出了此类的机要品质和与贯彻ScheduledThreadPoolExecutor功效相关的主意,关于怎么样行使数组完成优先队列请读者查阅相关文书档案):

static class DelayedWorkQueue extends AbstractQueue<Runnable> implements BlockingQueue<Runnable> {

  private static final int INITIAL_CAPACITY = 16;   // 数组初始化大小
  private RunnableScheduledFuture<?>[] queue = new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
  private final ReentrantLock lock = new ReentrantLock();   // 对添加和删除元素所使用的锁
  private int size = 0; // 当前队列中有效任务的个数

  private Thread leader = null; // 执行队列头部任务的线程
  private final Condition available = lock.newCondition();  // 除leader线程外其余线程的等待队列

  // 在对任务进行移动时,判断其是否为ScheduledFutureTask实例,如果是则维护其heapIndex属性
  private void setIndex(RunnableScheduledFuture<?> f, int idx) {
    if (f instanceof ScheduledFutureTask)
      ((ScheduledFutureTask)f).heapIndex = idx;
  }

  private void siftUp(int k, RunnableScheduledFuture<?> key) {/* 省略 */}

  private void siftDown(int k, RunnableScheduledFuture<?> key) {/* 省略 */}

  private int indexOf(Object x) {
    if (x != null) {
      if (x instanceof ScheduledFutureTask) {   // 如果为ScheduledFutureTask则可返回其heapIndex属性
        int i = ((ScheduledFutureTask) x).heapIndex;
        if (i >= 0 && i < size && queue[i] == x)
          return i;
      } else {  // 如果不为ScheduledFutureTask实例,则需要遍历队列查询当前元素的位置
        for (int i = 0; i < size; i++)
          if (x.equals(queue[i]))
            return i;
      }
    }
    return -1;
  }

  public boolean offer(Runnable x) {
    if (x == null)
      throw new NullPointerException();
    RunnableScheduledFuture<?> e = (RunnableScheduledFuture<?>)x;
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
      int i = size;
      if (i >= queue.length)
        grow(); // 队列容量不足,对其进行扩容
      size = i + 1;
      if (i == 0) { // 如果其为队列第一个元素,则将其放入队列头部
        queue[0] = e;
        setIndex(e, 0);
      } else {  //如果不为第一个元素,则通过堆的上移元素操作移动当前元素至合适的位置
        siftUp(i, e);
      }
      if (queue[0] == e) {  // 如果被更新的是队列头部元素,则更新记录的执行头部任务的线程
        leader = null;
        available.signal();
      }
    } finally {
      lock.unlock();
    }
    return true;
  }

  // 完成从队列拉取元素操作,并且将其从队列中移除
  private RunnableScheduledFuture<?> finishPoll(RunnableScheduledFuture<?> f) {
    int s = --size;
    RunnableScheduledFuture<?> x = queue[s];
    queue[s] = null;    // 将队列最尾部的元素置空
    if (s != 0) // 将最后一个元素放入第一个位置,并且将其下推至合适的位置
      siftDown(0, x);   // 这里idx置为0是因为当前方法的入参f都为队列的第一个元素
    setIndex(f, -1);
    return f;
  }

  // 尝试从队列(堆)中获取元素,如果没有元素或者元素的延迟时间还未到则返回空
  public RunnableScheduledFuture<?> poll() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
      RunnableScheduledFuture<?> first = queue[0];
      // 在此处代码控制了当从堆顶拉取元素时,如果元素的延迟时间还未达到,则不返回当前元素
      if (first == null || first.getDelay(NANOSECONDS) > 0)
        return null;
      else
        return finishPoll(first);   // 返回堆顶元素
    } finally {
      lock.unlock();
    }
  }

  // 通过无限for循环获取堆顶的元素,这里take()方法会阻塞当前线程,直至获取到了可执行的任务。
  // 可以看到,在第一次for循环中,如果堆顶不存在任务,则其会加入阻塞队列中,如果存在任务,但是
  // 其延迟时间还未到,那么当前线程会等待该延迟时间长的时间,然后查看任务是否可用,当获取到任务
  // 之后,其会将其从队列中移除,并且唤醒等待队列中其余等待的线程执行下一个任务
  public RunnableScheduledFuture<?> take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
      for (;;) {
        RunnableScheduledFuture<?> first = queue[0];
        if (first == null)
          available.await();    // 堆内没有元素,当前线程进入等待队列中
        else {
          long delay = first.getDelay(NANOSECONDS);
          if (delay <= 0)   // 堆顶元素延迟时间小于0,可立即获取任务
            return finishPoll(first);
          first = null;
          if (leader != null)
            available.await();  // 已经有线程在等待堆顶元素,则当前线程进入等待队列中
          else {
            Thread thisThread = Thread.currentThread();
            leader = thisThread;
            try {
              available.awaitNanos(delay);  // 当前线程等待一定时长后获取任务并执行
            } finally {
              if (leader == thisThread)
                leader = null;
            }
          }
        }
      }
    } finally {
      if (leader == null && queue[0] != null)
        available.signal(); // 当前线程获取完任务之后唤醒等待队列中的下一个线程执行下一个任务
      lock.unlock();
    }
  }
}

       从DelayedWorkQueue的take()和poll()方法能够看出来,对于队列中职责的等候时间的限制入眼是在那五个方法中贯彻的,假设职务的等待时间还未到,那么该方法就能够阻塞线程池中的线程,直至职责能够试行。

    Domain
Model 可分为两大类:Simple Domain Model 和 Rich Domain Model。

从Silverlight ⑤里向Javascript发送程序运维请求。
Silverlight 5端代码具体如下: 

2.4 scheduleAtFixedRate()和scheduleWithFixedDelay()方法

       前面大家对ScheduledThreadPoolExecutor的重大品质和主要内部类都开始展览了详细的助教,基本晚春经得以看来其是哪些兑现定期施行职责的功效的,接下去我们主要对客户端可以调用的重中之重格局开展简介,这里scheduleAtFixedRate()和scheduleWithFixedDelay()方法的兑现大旨是同1的,多个章程最微小的界别在于ScheduledFutureTask的setNextRun提姆e()方法的落成,该办法的兑现前边早已进展了讲课,我们这里则以scheduleAtFixedRate()方法的落实为例对该方法进行讲明。如下是该办法的求实贯彻:

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, 
                                              long period, TimeUnit unit) {
  if (command == null || unit == null)
    throw new NullPointerException();
  if (period <= 0)
    throw new IllegalArgumentException();
  ScheduledFutureTask<Void> sft =   // 封装客户端的任务实例
    new ScheduledFutureTask<Void>(command, null, 
                                  triggerTime(initialDelay, unit),unit.toNanos(period));
  RunnableScheduledFuture<Void> t = decorateTask(command, sft); // 对客户端任务实例进行装饰
  sft.outerTask = t;    // 初始化周期任务属性outerTask
  delayedExecute(t);    // 执行该任务
  return t;
}

       从上述代码能够看出来,scheduleAtFixedRate()首先对客户端职责实例实行了打包,装饰,并且初步化了包装后的天职实例的outerTask属性,最后调用delayedExecute()方法实施职分。如下是delayedExecute()方法的落到实处:

private void delayedExecute(RunnableScheduledFuture<?> task) {
  if (isShutdown())
    reject(task);
  else {
    super.getQueue().add(task); // 添加当前任务到任务队列中
    if (isShutdown() && !canRunInCurrentRunState(task.isPeriodic()) && remove(task))
      task.cancel(false);   // 双检查法再次判断当前线程池是否处于可用状态,不是则移除当前任务
    else
      ensurePrestart(); // 若线程池没有初始化,则进行一些初始化工作
  }
}

       上述方法为首要的实践职责的秘诀,该措施首先会将职务参与到职分队列中,借使线程池已经初叶化过,那么该任务就能够有等待的线程推行该职分。在进入到职分队列之后经过双检查法检查线程池是还是不是已经shutdown了,要是是则将该任务从义务队列中移除。假设当前线程池未有shutdown,就调用承袭自ThreadPoolExecutor的ensurePrestart()方法,该方法会对线程池举办一些开端化职业,如开首化焦点线程,然后依次线程会调用上述等待队列的take()方法获得职分奉行。

  • Simple Domain Model
    往往是业务对象和数码库表之间1对壹的通讯。你曾经见过的两种情势 ——
    Active Record、Table Data Gateway,以及 Data
    Mapper,全数这一个与数据库相关的设计形式 ——
    能够扶助你把与数据库相关的逻辑组织成二个 Domain
    Model。
  • Rich Domain
    Model 包蕴复杂的,使用持续机制紧凑联系在一起的目的互连网,在本书和 GoF
    壹书中介绍的浩大情势起着杠杆成效。Rich Domain Models
    往往是柔性的,精心测试过的,不断重构的,而且与它们所抒发的领域所需的作业逻辑严峻耦合。

HtmlPage.Window.Invoke(“Javascript函数情势”, “传值-Oyiboy”);

   
选取哪类 Domain
Model 类型取决于你的应用情状。若是您正在建构的是一个特别轻便的表单处理web 应用,没供给建设构造 Rich Domain
Model。然则,要是您正在编写制定二个价值数百万的营业所内联网架构的为主库,那么拼命付出三个Rich Domain Model
正是值得的,它可感到您提供三个纯粹表明业务进度的平台,并得以让您快速传输数据。

经过上述代码能够平素在Silverlight
五里运营Javascript的本子代码,并发送供给的多少出来。

    MartinFowler 在 PoEAA 中并且归纳介绍了二种 Domain Model。而 Eric 埃文思 的
Domain Driven Design 一书,则一心专注于 Rich Domain Model
的举行应用和开采进度。

二、Javascript发言,Silverlight 5倾听

    View
用于拍卖全数表现层方面包车型客车主题材料。View 从 Model
获取数据,并得以把它格式化成用于 web 页的 HTML,用于 web 服务的
XML,或用来 email 的文本。

Javascript使用ajax获取服务器端数据后发送给Silverlight
伍,以达到Silverlight 5与服务器端的竞相效能。
Silverlight 五端代码具体如下:

   
大多的MVC情势的落成也都使用1个View Model或Application
Model的概念,Controller是联系的媒人,架起世界模型和用户分界面之间的桥梁,属于表现层。为了View的轻便性,Controller负担处理大概将世界模型转变来3个View
Model,这常常称为数据传输对象(DTO)

//设置值
[ScriptableMember()]//那行是至关重要,必须有那一个javascript工夫请求到这一个格局
public void setVal(string D)
{
this.textView.Text = D;
}
//javascript主动供给重回值
[ScriptableMember()]
public string returnVal()
{
return this.textView.Text;
}

    DomainModel != ViewModel

Html代码调解:
急需在Silverlight
伍插件的object代码内里增添以下参数设置句,以到达插件在加载后获得siliverlight对象。

   
DomainModel代表着相应的域,但ViewModel却是为View的须要而创造。那两个之间也许(一般景况下都)是例外的,其它DomainModel是多少增加行为的组合体,是由复杂的变量类型组成的还要具备等级次序。而ViewModel只是由局地String等轻松变量类型组成。假设想移除冗余并且轻巧导致出错的O凯雷德M代码,能够采用AutoMapper.假使想要领会越来越多。

<param name=”onLoad” value=”siliverLoaded” />

   
那么领域模型(Domain Model
)和视图模型(View Model)有哪些区别呢?

Javascript代码具体如下:

   
在ASP.NET MVC的应用程序中时常能够能够见见View
Model,常常大家都觉着世界模型和视图模型是同二个事物。那极其是把世界模型包涵在数量传输对象DTO里的时候,譬喻使用Entity
Framework之类的OCRUISERM工具生成的实业。在这种情景下,领域模型和视图模型蕴涵的实业特别相似,都以1对简约的CRUD操作。

//siliverlight对象
var siliverlightObj = null;
//上面那个HTML代码内设置的Silverlight 5 onLoad事件触发的函数
function siliverLoaded(sender, args) {
siliverlightObj = sender.getHost();
}

//以下代码中的.buttonSet和.buttonReu是两个带这些class的按钮,按钮就不详细写出来了
//这个是运行Silverlight 5内的setVal方法
$(".buttonSet").click(function () {
siliverlightObj.Content.Main.setVal("javascript传入值-Oyiboy");
})
//这个是运行Silverlight 5内的returnVal方法
$(".buttonReu").click(function () {
alert(siliverlightObj.Content.Main.returnVal());
});
// hovertree.com

   
那么些实体有无数属性,有一样或看似的称谓,你能够很轻易地映射领域实体对应视图模型中的多少个脾气。可是,这么些相似的习性也也许略有差异,譬如类型也许格式。举个例子,用户填写的用户分界面包车型客车一特性子,他在视图模型里或者是三个“Nullable”的。

 

   
另1方面,领域实体大概要求1个透过证实的合法的值,所以必要2个在用户分界面包车型地铁园地模型之间的改换。另四个事例是,用户分界面恐怕会来得3个滑块,用于用户采纳多少天过后提交他的订单。在这种情景下,视图模型只怕应用3个整数属性来表示,领域模型平日是2个日期值。

如上多少个艺术,灵活利用的活基本上就全盘减轻了Silverlight
五与劳动器端之间的调换,行吗,即便那篇的东西的大旨是Silverlight
5与Javascript,但最后指标照旧Silverlight
伍与服务器端的交互,反正ajax也不是怎么着新物,所以就跳过了。

   
视图模型通常只包括领域模型的三个子集,而且只包涵分界面上所须要的属性。此外,视图模型恐怕是一个领域模型树的扁平版本,举个例子,2个Customer实体有多个Address,而那又是二个整机,它包含街道地址,邮编,国家等。叁个Customer
视图模型用于彰显数据,将地点数据拉平填充到视图模型类里。

感想:通过Silverlight
伍的目的siliverlightObj.Content.Main这一大窜东西来看,siliverlightObj还是能作更多的事了,具体还要稳步查究了,倘若之后有要求选拔的话,还会出这么些的辨证文章吧,可能。

   
此外假使1个View需求同期管理多少个领域模型,View
Model正是那多少个Domain
Model的总量。领域模型和视图模型之间有好多一般的地点,我们平时干脆就把Domain
Model当作View Model来使用了。
   
上边钻探了世界模型和视图模型的相似性,大家来看望都有三种艺术把世界模型转变为视图模型,平常有三种格局:

补漏: 
关于siliverlightObj.Content.Main中的Main是指在Silverlight
中app.xaml的Application_Startup事件中登记的拜访名称,具体代码如下:

  • 把世界模型当作视图模型来用,也正是小圈子模型正是视图模型,半数以上都以那样用的。
  • 视图模型里面包罗二个天地模型,定义3个视图模型,里面富含了一个世界模型,通过品质方式进行访问。
  • 将世界模型映射到视图模型,领域模型并不曾直接照射到视图模型,供给处理这种映射关系。

private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = new MainPage();
System.Windows.Browser.HtmlPage.RegisterScriptableObject(“Main”,
this.RootVisual);
}

   
我们不建议直接把世界模型实体暴光给视图,因为有许多轻微之处,恐怕导致你混合业务和表示层的逻辑,无论是领域实体的属性展现照旧职业的验证规则,那都以应用程序处理的区别方面。

从代码中可见,要是有多个xaml页的话,只要在此处登记差异的称呼就足以引用分化xaml页内证明的Javascript方法了。 
碰巧整理代码时在APP.xaml开掘那句代码才想起把这些给漏了,后天补回。

   
直接将你的园地模型作为Conroller上的管理参数面前境遇着安全危机,因为Controller或然Model
binder必须确保属性验证和用户无法修改她要好不可能改改的习性(举个例子,用户手动更新了贰个潜伏的输入值,或增添2个外加的属性值,而那一个并不是分界面上的成分,但却凑巧领域模型实体的习性,这种高风险叫做“over-posting”),纵然对当前版本的圈子模型做了天经地义的评释,领域模型今后只怕做了改观修改,并从未出现编写翻译错误大概警告,只怕引致新的高危害。
   
咱俩理应制止选择前三种办法将世界模型调换来视图模型,推荐使用第三种艺术,定义单独的视图模型类。做这种领域模型到视图模型的转移工作是一种重复性的劳作,已经有多少个工具得以帮忙您来实现那项专门的工作。最常用的八个工具正是.NET
社区的开源项目AutoMapper。

silverlight加密:http://keleyi.com/tool/md5.htm

 (私家明白:针对域模型与视图模型,有的时候候要求看具体的政工场景,一般意况下能够遵从上述将DomainModel和ViewModel实行数量映射,以防止有个别安全性难题;然而也得以将DomainModel当成ViewModel来行使也是足以的,通过在系统贯彻、业务逻辑操作和剖断上是足以确认保障工作安全性的。就是前者也要实行决断以保障安全性。所以,如故看现实业务种类的运用条件与须求来决定动用哪一类艺术来完成。

转自:http://hovertree.com/h/bjaf/silverlight5.htm

 

silverlight数字挂钟:
公海赌船网站 1

文章转发自:http://www.cnblogs.com/shanyou/archive/2010/04/03/1703501.html

http://roucheng.cnblogs.com/

相关文章