创建一个线程

通过实例化一个Thread类型的对象可以创建一个线程.THread类封装可运行的对象.如上所述,Java定义了两种可运行对象的方法:
实现Runnable接口.
扩展Thread类
本章的多数示例使用的是实现Runnable接口的方法.切记,两种方法都要用到Thread类来实例化,访问及控制线程.唯一不同的就在与线程的类是如何创建的.
Runnable接口抽象了一个可执行代码单元.可以在实现runnable接口的任何对象上构造线程.runnable只定义了一个名为run()的方法,其声明如下:
public void run();
在run()内,可以定义组成新线程的代码.run()可以调用其他方法,使用其他类,可以像主线程那样声明变量,理解这一点很重要.唯一的区别在于run()是为程序中的另一个并发执行的线程建立进入点.这个线程在run()返回时结束.
在创建一个实现Runnable接口的类后,会在这个类的对象上实例化一个Thread类型的对象.Thread定义了几个构造函数.其中我们首先用到的构造函数如下所示:
Thread(Runnable threadob)
在这个构造函数中,threadOb是一个实现了Runnable接口的类的实例.这个函数定义了从哪里开始执行线程.
新线程创建之后,直到调用他的start()方法时,他才会运行,该方法是在Thread中声明的,其实,start()执行的是对run()的调用.start()方法如下所示:
void start();
下面的实例创建了一个新线程,并且开始运行该线程:
public class test2
{
    // @param args
    public static void main(String args[])
    {
     MyThread mt = new MyThread("child#1");
     
     Thread newThrd = new Thread(mt);
     newThrd.start();
     
     for(int i=0;i<50;i++)
     {
         System.out.print(".");
         try {
             Thread.sleep(100);
         }catch(InterruptedException exc) {
             System.out.println("main thread  interrupted");
         }
     }
     System.out.println("main thread ending");
    }
}
class MyThread implements Runnable
{
    String thrdName;
    
    MyThread(String name)
    {
        thrdName = name;
    }
    
    public void run()
    {
        System.out.println(thrdName+" start");
        try {
            for(int count=0;count<10;count++)
            {
                Thread.sleep(400);
                System.out.println(thrdName+"  count is "+count);
            }
        }catch(InterruptedException exc) {
            System.out.println(thrdName+"  interrupted");
        }
    }
}
我们详细介绍一下这个程序,首先,MyThread类实现了Runnable接口.这就意味着MyThread类型的对象适于作为线程使用,并且可以将其传送给Thread构造函数.
在run()内部,建立了一个从0到9进行统计的循环.注意对sleep()的调用.sleep()方法会使调用他的线程挂起已毫秒为单位的制定周期.其基本形式如下所示:
static void sleep(long millisecounds) throws InterruptedException
挂起的毫秒数在millisecound中指定,该方法可以抛出InterruptedException,因此必须在try块中调用.sleep()方法也有第二种形式,允许以毫秒和纳秒(如果需要这一级别的精度的话)为单位指定周期.在run()中,每次经过循环时,sleep()会将线程暂停400毫秒,这一可以使线程的运行变慢,以便你有时间观察其执行:
在main()中,可以按照下面的语句序列创建一个新的thread对象:
    MyThread mt = new MyThread("child#1");
    Thread newThrd = new Thread(mt);
    newThrd.start();
如注释提示的那样,首先创建的是一个MyThread对象.该对象用于构造一个Thread对象,因为MyThread类实现Runnable接口,所以这是可行的.最后,新线程通过调用start()开始执行.这会启动子线程的run()方法.调用start()后,执行返回到main(),并且进入main()的for循环.这个循环迭代50次,每次暂停100毫秒,这样两个线程继续执行,共享单核系统中的CPU,知道他们的循环结束为止.
输出:
.child#1 start
....child#1 count is 0
....child#1 count is 1
....child#1 count is 2
....child#1 count is 3
....child#1 count is 4
....child#1 count is 5
....child#1 count is 6
....child#1 count is 7
...child#1 count is 8
.....child#1 count is 9
.........main thread ending
在这个线程示例中,还有一个值得注意的地方.为了演示主线程和mt的并发执行,必须使main()在mt结束以后才终止.在这里是铜鼓两个线程的时间差实现这一点的.因为他main()的for循环中调用sleep()导致延迟5秒,但是run()循环内的总延迟只有4秒,所以run()比main()早结束大约1秒,结果主线程和mt都将并发执行,直到mt结束,在这之后大约1秒,main()也会结束.
虽然这种使用时间差来确保main()最后结束的方法对于这个简单的例子来说是足够了,但是在实际的程序中却不会这么做,Java提供了更好的方法来等待线程结束.但是,这种方法用于接下来的几个程序是没问题的.
最后一点:在多线程程序中,你往往想让主线程做为最后一个完成运行的线程.一般来说,程序会在他们的所有线程结束前继续运行,因此将主线程作为最后一个结束的线程是没必要的.然而,这却是一个应该遵循的良好的编程习惯,特别是当第一次学习多线程程序时,更是如此.
问:在多线程程序中,为什么推荐主线程作为最后结束的线程?
答:主线程是有序关闭程序的一个很方便的地方.他也为程序提供了定义良好的退出点.因此使其最后结束很合理.幸运的是,如你将要看到的,使主线程等待子线程完成之后再结束并不是什么难事.