• Java多线程——<二>将任务交给线程,线程声明及启动


    一、任务和线程

      《thinking in java》中专门有一小节中对线程和任务两个概念进行了具体的区分,这也恰好说明任务和线程是有区别的。

      正如前文所提到的,任务只是一段代码,一段要达成你目的的代码,这段代码写在哪,怎么写其实无所谓,只是因为你希望java的多线程机制能够识别并调用你编写的任务,所以规定了Runnable接口,让你的任务来实现该接口,把你想做的工作在实现该接口的run方法中实现。

      那么,已经定义了任务类,那任务和线程有什么关系呢?

      java的线程是用来驱动任务执行的,也就是说你得把任务挂载到一个线程上,这样该线程才能驱动你定义的任务来执行。

    二、定义线程

      1.显示的定义线程的过程就是将任务附着到线程的过程。线程Thread自身并不执行任何操作,它只是用来被多线程机制调用,并驱动赋予它的任务。

      如前次文章提到的任务类定义如下:

    public class Task implements Runnable {
        protected int countDown = 10;
        private static int taskCount = 0 ;
        private final int id = taskCount++;
        public Task(){}
        public Task(int countDown){
            this.countDown = countDown;
        }
        public String status(){
            return "#"+id+"("+(countDown>0?countDown:"Task!")+").    ";
        }
        @Override
        public void run() {
            while(countDown-->0){
                System.out.print(status());
                Thread.yield();
            }
        }
    }

      声明线程并将任务附着到该线程上:

    Thread t = new Thread(new Task());

      这样,任务就附着给了线程,下面就是让线程启动,只需要如下的调用:

    t.start();

      至此,线程声明ok。

      有时,我会想,是不是像任务和线程的概念分离一样,此时只是声明了线程,而java的线程机制并不会调用该线程运行,还需要特殊的调用才能实现多线程执行。但是下面的一段代码告诉我,Thread类的start方法就是触发了java的多线程机制,使得java的多线程能够调用该线程

    public static void main(String[] args){
            Thread t = new Thread(new Task());
            t.start();
            System.out.println("Waiting for Task");
    }

    输出结果如下:

    Waiting for Task
    #0(9).    #0(8).    #0(7).    #0(6).    #0(5).    #0(4).    #0(3).    #0(2).    #0(1).    #0(Task!).    

      先输出“Waiting for Task”证明调用完start()方法后,立即返回了主程序,并开始执行下面的语句。而你声明的t线程已经去被java的多线程机制调用,并驱动着它的任务运行了。

      2.补充

      想看到更多的线程任务运行,可以用下面的这段代码

    public static void main(String[] args){
            for(int i = 0 ; i < 5 ; i++){
                new Thread(new Task()).start();
            }
            System.out.println("Waiting for Task");
    }

      输出如下:

    Waiting for Task
    #0(9).    #2(9).    #4(9).    #0(8).    #2(8).    #4(8).    #0(7).    #2(7).    #4(7).    #0(6).    #2(6).    #4(6).    #0(5).    #2(5).    #4(5).    #0(4).    #2(4).    #4(4).    #3(9).    #2(3).    #4(3).    #2(2).    #4(2).    #2(1).    #4(1).    #2(Task!).    #4(Task!).    #1(9).    #0(3).    #0(2).    #0(1).    #0(Task!).    #3(8).    #1(8).    #3(7).    #1(7).    #3(6).    #1(6).    #3(5).    #3(4).    #3(3).    #3(2).    #3(1).    #3(Task!).    #1(5).    #1(4).    #1(3).    #1(2).    #1(1).    #1(Task!).    

      上面的输出说明不同任务的执行在线程被换进换出时混在了一起——由线程调度器自动控制。不同版本的jdk线程调度方式不同,所以产生的结果也不相同。

      这里涉及了垃圾回收器的一个问题,每个Thread都注册了它自己,因此确实有一个对它的引用,而且在它的任务退出其run并死亡之前,垃圾回收器无法清除它。

    注:以上代码均来自《thinking in java》,内容大部分是个人理解和总结,如有错误请各位指正

  • 相关阅读:
    SQLDataSet中执行DDL语句
    在SQL语句中使用参数
    delphi排序算法
    ClientDataSet中的PacketRecords属性,减轻网络负载,提升服务器与客户端性能
    ClientDataSet中修改,删除,添加数据和Delta属性
    SQLMonitor观察DBE的执行行为
    this的指向(慢慢添加)
    如何在Html的CSS中去除<li>标签前面小黑点,和ul、LI部分属性方法
    AJAX的工作原理及其优缺点
    IE浏览器和Firefox浏览器兼容性问题及解决办法
  • 原文地址:https://www.cnblogs.com/brolanda/p/4701334.html
Copyright © 2020-2023  润新知