1.*一个程序运行后至少有一个进程,一个进程里可以包含多个线程,但至少要包含一个线程。*

    2.线程在程序中是独立的、并发的执行流。
 
实现线程的方法一:    继承Thread类创建线程类
 
        1.定义Thread类的子类,并重写该类的run方法,该run方法的方法体就是代         表线程需要完成的任务,
因此,我们经常把run方法称为线程执行体。
2.创建Thread子类的实例,及时创建了线程对象。
3.用线程对象的start方法来启动该线程。

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


结果:Thread-0和Thread-1两条线程输出的i变量不连续,因为i变量是FirstThread的实例属性,而不是局部变量 但每次创建线程对象都需要创建一个FirstThread对象,所以Thread-0和Thread-1不能共享该实例属性。

实现线程的方法二:    实现Runnable接口创建线程类

1.定义Runnable接口的实现类,并重写该接口的run方法,该run方法的方法体是该线程的线程执行体。

2.创建Runnable实现类的实例,并以此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。

        3.调用线程对象的start方法来启动线程。

  例:

 


  
  1. //创建Runnable实现类的对象 
  2.   SecondThread st = new SecondThread(); 
  3.   //以Runnable实现类的对象作为Thread的target来创建Thread对象,即线程对象 
  4.   new Thread(st);//或new Thread(st,"新线程1");直接指定一个名字 

注意:

     Runnable对象仅仅作为Thread对象的target,Runnable实现类里包含的run方法 仅作为线程执行体。而实际的线程对象依然是Thread实例,只是该Thread 线程负责执行其target的run方法。java语言的Thread必须使用Runnable对象的run方法作为线程执行体。

例:


  
  1. package bin; 
  2. public class SecondThread implements Runnable 
  3.     private int i; 
  4.     public void run() 
  5.     { 
  6.         for(;i<100;i++)  
  7.         { 
  8.             System.out.println(Thread.currentThread().getName() + " " + i);  
  9.         } 
  10.     }    
  11.     public static void main(String[] args) 
  12.     { 
  13.         for(int i =0;i<100;i++) 
  14.         { 
  15.             System.out.println(Thread.currentThread().getName() + " " + i);  
  16.             if(i==20
  17.             { 
  18.                 SecondThread st = new SecondThread(); 
  19.                 new Thread(st,"新线程1").start();   
  20.                 new Thread(st,"新线程2").start();   
  21.             }    
  22.         }    
  23.     } 
  24. /* 结果:两条子线程的i变量是连续的,也就是采用Runnable接口的方式创建的多条线程
  25. 可以共享线程类的实例属性。 因为:程序创建的Runnable对象只是线程的target,而多线程可以共享
  26. 同一个target,所以多线程可以共享同一个线程类(实际上应该是线程的target类)的实力属性。 */

对比FirstThread和SecondThread中的run方法 :

           使用继承Thread时获取当前线程对象比较简单,直接使用this就可以 但使用实现Runnable接口时要获得当前线程对象必须使用Thread.currentThread()方法。

注:

    1.启动线程使用start方法,而不是run方法,永远不要调用线程对象的run方法!调用start方法来启动线程,系统会把该run方法当成线程执行体来处理,但如果直接调用run方法,则run方法直接就会被执行,而且在run方法返回之前其他线程无法并发执行(系统当成普通对象执行,而不是线程执行体)。

    2.不要对处于死亡状态的线程调用start()方法,程序只能对新建状态的线程调用start()方法,对于新建状态的线程两次调用start()方法也是错误的。