转载

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》,内容大部分是个人理解和总结,如有错误请各位指正

正文到此结束
Loading...