1.进程和线程

  进程是运行中的程序,每个进程拥有独立的资源,在处理器上可以并发执行,多个进程之间互不影响。
  线程是进程的执行单元,一个进程被初始化后,主线程就被创建了。一个线程可以有自己的堆栈,计数器和局部变量,但系统资源和其父进程的其他线程所共享。一个线程可以创建和撤销另外一个线程,线程本身的调度和管理由进程负责完成。


 2.线程的创建和启动


  创建线程有如下两种方法:


  2.1 继承Thread类创建线程类


  具体步骤如下:
    a. 定义Thread类的子类,并重写run()方法。run()方法的方法体就是线程需要执行的任务;
    b. 创建Thread子类的实例;
    c. 用线程对象的start()方法来启动线程。

 

 

  1. //通过继承Thread类来创建线程类  
  2. public class FirstThread extends Thread  
  3. {  
  4.     private int i ;  
  5.     //重写run方法,run方法的方法体就是线程执行体  
  6.     public void run()  
  7.     {  
  8.         for ( ; i < 100 ; i++ )  
  9.         {  
  10.             //当线程类继承Thread类时,可以直接调用getName()方法来返回当前线程的名。  
  11.             //如果想获取当前线程,直接使用this即可  
  12.             //Thread对象的getName返回当前该线程的名字  
  13.             System.out.println(getName() +  " " + i);  
  14.         }  
  15.     }  
  16.       
  17.     public static void main(String[] args)   
  18.     {  
  19.         for (int i = 0; i < 100;  i++)  
  20.         {  
  21.             //调用Thread的currentThread方法获取当前线程  
  22.             System.out.println(Thread.currentThread().getName() +  " " + i);  
  23.             if (i == 20)  
  24.             {  
  25.                 //创建、并启动第一条线程  
  26.                 new FirstThread().start();  
  27.                 //创建、并启动第二条线程  
  28.                 new FirstThread().start();  
  29.             }  
  30.         }  
  31.     }  

 

需要注意的是:该程序有三个线程,当i=20时启动另外两个线程。另外,两个线程不能共享实例属性i,他们输     出的i值不连续。


  2.2 实现Runnable接口创建线程类


  具体步骤如下:
  a.  定义Runnable接口实现的类,并重写run()方法;
  b.  创建其实例,并把这个实例作为Thread类的Target来创建Thread对象;
  c.  执行Thread对象的start()方法。

 

  1. //通过实现Runnable接口来创建线程类  
  2. public class SecondThread implements Runnable  
  3. {  
  4.     private int i ;  
  5.     //run方法同样是线程执行体  
  6.     public void run()  
  7.     {  
  8.         for ( ; i < 100 ; i++ )  
  9.         {  
  10.             //当线程类实现Runnable接口时,  
  11.             //如果想获取当前线程,只能用Thread.currentThread()方法。  
  12.             System.out.println(Thread.currentThread().getName() + "  " + i);  
  13.         }  
  14.     }  
  15.       
  16.     public static void main(String[] args)   
  17.     {  
  18.         for (int i = 0; i < 100;  i++)  
  19.         {  
  20.             System.out.println(Thread.currentThread().getName() + "  " + i);  
  21.             if (i == 20)  
  22.             {  
  23.                 SecondThread st = new SecondThread();  
  24.                 //通过new Thread(target , name)方法创建新线程  
  25.                 new Thread(st , "新线程1").start();  
  26.                 new Thread(st , "新线程2").start();  
  27.             }  
  28.         }  
  29.     }  

   以同一个实现Runnable接口的线程类实例为target对象的多条线程,可以共享线程类的实例属性。上面代码中     的两个线程输出的i值连续。

3. 线程的生命周期

   线程的生命周期如下图所示:

 

 

    需要注意如下几点:

    a. 当使用new关键字创建一个线程时,该线程就处于新建状态;而该对象调用了start()之后,该线程就处于就绪状态,表示该线程可以运行,至于何时运行,取决于Java虚拟机中线程调度器的调度。

    b. 启动线程调用的是start()方法而非run()方法。调用start()方法启动线程,系统会把该run()方法当做线程的执行体去处理,否则就不会把其作为一个线程去看,从而立刻执行。

    c. 其他线程和主线程具有同等地位,不会因为主线程的结束而随之结束。不能对已经死亡的线程调用start()方法。

 

  4. 线程的控制

  下面是一些控制线程的常用方法: 

    a. join

    它的作用是使得一个线程等待另外一个线程执行完毕在开始继续执行。在需要等待的线程中调用被等待线程中的join()方法。

    b. 后台线程

    后台线程是在后台运行,为其他线程提供服务。特征是,如果前台进程死亡,它也随之死亡。调用Thread对象的setDaemon(true)方法可以将其设置为后台进程。前台线程创建的子线程默认为前台线程,后台线程创建的子线程默认为后台线程。为保证正确的设置setDaemon(true)方法必须在start()之前调用。

    c. 线程睡眠sleep

    Thread类所提供的sleep方法可以是当前执行的线程休眠处于阻塞状态一段规定的时间,即使系统中没有其他可运行的线程,它也不会被调用。对其他的线程没有优先级的要求,都可以获得处理器资源。

    d. 线程让步yield

    Thread类的静态方法yield是当前运行的线程转入就绪状态,并不会阻塞该线程,只是让系统的线程调度器重新调度一次