zoukankan      html  css  js  c++  java
  • 并发编程(2) 之 线程驱动任务

    前序:
         我们前面说了,我们的程序是可以分成若干个程序片段的,而每一个程序片段我们都可以用来做为一在多个任务;当然做为独立可运行的任务将更为理想化;在多线程来实现并发的手段时,我们常常将没一个任务用一个独立的线程来进行驱动;
       
          下面是一个简单的线程来驱动我们的一个任务的执行;
    1.任务的描述

    /**
     * 一个简单的任务类
     * @author liuwei 继承于Runnable接口,并提供Run方法的实现
     * Runnable为描述任务的方式
     */
    public class SimpleTask implements Runnable {
        /**
         * 任务执行总数
         */
        protected int countDown = 10;
    
        private static int taskCount = 0;
    
        /**
         * 任务执行次数id
         */
        private final int id = taskCount++;
    
        /**
         * 无参构造函数
         */
        public SimpleTask() {
        }
        /**
         * 带参构造函数
         * @param countDown
         */
        public SimpleTask(int countDown) {
            this.countDown = countDown;
        }
        /**
         * 显示任务的信息
         * @return
         */
        public String status() {
             return "#" + id + "(" + (countDown > 0? String.valueOf 
             (countDown):"SimpleTask!")+ "), ";
        }
    
        /**
         * 任务的执行方法
         */
        public void run() {
        while (countDown-- > 0) {
           System.out.print(status());
           /**
            * 对线程调度器的一种建议,即java线程机制的一部分,
             * 可以将cpu从一个线程转到另一个线程,且类似告诉
             * 别人,我这里目前不需要占用现在的内存资源了;
             * 我们可以说它是一个上下文切换的一个动作;
             */
           Thread.yield();
               }
        }
    }



    这个单独的任务,并不能够独立的执行;且也不具有产生任务内在的线程能力;而且,要实现线程行为,还必须显式的将这个任务附到线程上去;

    2.线程的描述
       在java中,将Runnable对象转变成工作任务的传统方式就是将它将给线程,并由线程来驱动它执行;这一点和Quartz里的Job与Scheduler有点相似;即作业不能够自己运行,它需要在Scheduler上进行注册后,由任务调度器来负责管理它;
       下面我们来实现一个线程驱动任务的执行;

    /**
     * 一个线程来驱动任务的执行
     * @author liuwei
     */
    public class TreadDriverTask {
        
      /**
       * 当通过线程thread的start方法调用任务的run方法的时候,
        * main函数所对应的线程将继续执行System的语句;它不会等待
        * thread执行完毕后再执行System操作;
        * 我们前面说过,一个线程就是在进程中有一个单一的顺序控制流;
        * @param args
        */
       public static void main(String[] args){ 
           Thread thread=new Thread(new SimpleTask());
           thread.start();
           System.out.println("---->main执行的现成与线程thread是相互独立
            的!");
       }
    }


    它的执行情况为:
    ---->main执行的现成与线程thread是相互独立的!
    #0(9), #0(8), #0(7), #0(6), #0(5), #0(4), #0(3), #0(2), #0(1), #0(SimpleTask!),

    我们来看看多个现在执行多个任务的时候,它是一个什么样的情况!

    /**
     * 多个线程来驱动任务的执行
     * @author liuwei
     */
    public class MultThreadDriverTask {
        
      /**
       * 当通过线程thread的start方法调用任务的run方法的时候,
        * main函数所对应的线程将继续执行System的语句;它不会等待
        * thread执行完毕后再执行System操作;
        * 我们前面说过,一个线程就是在进程中有一个单一的顺序控制流;
        * @param args
        */
       public static void main(String[] args){ 
        for(int i=0;i<5;i++){
        new Thread(new SimpleTask()).start();
             }
         System.out.println("---->waiting for ......!");
       }
    }


    它的执行效果如下:
    #0(9), #1(9), ---->waiting for ......!
    #0(8), #3(9), #1(8), #3(8), #2(9), #1(7), #4(9), #0(7), #2(8), #4(8), #0(6), #2(7), #4(7), #0(5), #2(6), #4(6), #0(4), #2(5), #4(5), #0(3), #2(4), #4(4), #0(2), #2(3), #4(3), #0(1), #3(7), #2(2), #4(2), #1(6), #0(SimpleTask!), #3(6), #2(1), #1(5), #4(1), #3(5), #2(SimpleTask!), #1(4), #4(SimpleTask!), #3(4), #1(3), #3(3), #1(2), #3(2), #1(1), #3(1), #1(SimpleTask!), #3(SimpleTask!),
    我们可以看出:
    当通过for循环分别创建5个线程的时候,在创建的过程中是有一定的时间差的;比如我在创建第5个线程的时候,可能第一个创建的线程已经开始执行 附属任务的run方法;且所有线程创建完毕后(这个是由main所在线程内完成的),则执行了System操作;而前面创建的5个线程,他们将自己运行自 己的;
    另一个特点是,他们的输出是相互混乱的;因为线程间的相互切换是由线程调度器来进行自动控制的;对于单处理器的环境,则调度器将将cpu时间片分给不同的线程进行占用;而对于多处理器的环境,则线程调度器将会在多个处理器之间默默的分发线程;

    3.线程调度机制的非确定性
      对于上面的结果,可能每一次运行的输出也是不一样的;因为这就是线程调度机制的非确定性,同样,对于不同的jdk版本,其运行的输入也不一样;首先对于同 一jdk版本下的运行结果的不一致,是因为对于每一次的运行,它的cpu时间片的分配可能进行不同的分配(单处理器环境),它的任务处理器也可能每次分配 的线程也不一致(多处理器环境);对于不同jdk版本,在sun的早期jdk,cpu时间的切片动作不是很频繁,可能上面的5个线程,线程1执行完后,线 程2才会执行;它启动所有线程的代价相对现有jdk的启动可能代价更高;现在的jdk,时间切片行为更为完善,每个线程看起来都会获得更加正规的服务(处 理器服务于它);

    4.main函数为何没有对启动的线程进行异常捕获且没有引用的Thread没有被垃圾回收
       在上面的main方法里创建Thread对象的时候,它并没有去捕获这些对象的引用;通常大家都知道,对于一个对象没有引用指向他,则它将被垃圾回收器定 时回收;但对于thread就不同了,每个thread都注册了自己,因为确实有一个引用指向它,且只有当run方法执行完毕后,垃圾回收器才会清楚它; 且我们说过了mian方法,与启动的每一个thread是相互独立的,我们不能够在A线程1去捕获B线程下可能存在的异常;

  • 相关阅读:
    MS CRM 2011 RC中的新特性(4)——活动方面之批量编辑、自定义活动
    最近的一些有关MS CRM 2011的更新
    MS CRM 2011 RC中的新特性(6)——连接
    MS CRM 2011 RC中的新特性(7)—仪表板
    参加MS CRM2011深度培训课程——第一天
    MS CRM 2011插件调试工具
    MS CRM2011实体介绍(四)——目标管理方面的实体
    MS CRM 2011 RC中的新特性(3)——客户服务管理方面
    MS CRM 2011 RC中的新特性(8)—数据管理
    ExtAspNet 登陆
  • 原文地址:https://www.cnblogs.com/chasewade/p/3372253.html
Copyright © 2011-2022 走看看