您的位置:首页 > 编程语言 > Java开发

java创建线程的两种方法比较

2015-09-21 15:21 591 查看
在Java中创建线程有两种方法:继承Thread类和实现Runnable接口。

一、继承Thread类创建线程类(Thread类已经实现了 Runnable接口)

1、Thread类的构造方法有8个,但常用的只有4个,分别为:

Thread类中的两个最主要的方法:

(1)run()—包含线程运行时所执行的代码,即线程需要完成的任务,是线程执行体。

(2)start()—用于启动线程。

2、通过继承Thread类来创建并启动多线程的步骤:

(1)定义Thread类的子类,并覆盖该类的run()方法。

(2)创建Thread子类的实例,即创建线程对象。

(3)用线程对象的start()方法来启动该线程。

例程1:

Java 代码

   1. public class Thread1 extends Thread{  

   2.     public void run(){  

   3.         System.out.println(this.getName());  

   4.     }  

   5.     public static void main(String args[]){  

   6.         System.out.println(Thread.currentThread().getName());  

   7.         Thread1 thread1 = new Thread1();  

   8.         Thread1 thread2 = new Thread1();  

   9.         thread1.start();  

  10.         thread2.start();  

  11.     }  

  12. }  

public class Thread1 extends Thread{

    public void run(){

        System.out.println(this.getName());

    }

    public static void main(String args[]){

        System.out.println(Thread.currentThread().getName());

        Thread1 thread1 = new Thread1();

        Thread1 thread2 = new Thread1();

        thread1.start();

        thread2.start();

    }

}

程序的运行结果如下:

main

Thread-0

Thread-1

注意:程序中两条线程并发执行时,每次的执行结果是会变化的。这是因为,如果多个没有同步约束关系的线程并发执行时,调度线程将不能保证哪个线程先执行及其持续的时间,在不同平台上,或在同一平台上不同时刻的多次运行可能会得到不同的结果。

Java中对于线程启动后唯一的能够保障的就是:“每个线程都将启动,每个线程都会执行结束”。但谁会先执行谁会后执行,将没有保障,也就是说,就算一个线程在另一个线程之前启动,也无法保障该线程一定在另一个线程之前执行完毕。

程序分析如下:

(1)任何一个Java程序都必须有一个主线程。主线程的线程执行体不是由run()方法来确定的,而是由main()方法来确定的:main()方法的方法体代表主线程的线程执行体。

(1)上面程序用到线程的两个方法:

Thread.currentThread():currentThread()是Thread类的静态方法,该方法总是返回当前正在执行的线程对象的引用。

getName():该方法是Thread类的实例方法,该方法返回调用该方法的线程的名字。

(3)程序可以通过setName(String name)方法为线程设置名字,也可以通过getName()方法返回指定线程的名字。在默认情况下,主线程的名字为main,用户启动的多条线程的名字依次为:Thread-0、Thread-1、Thread-2、……、Thread-n等。

(4)一个线程只能被启动一次。否则会抛出java.lang.IllegalThreadStateException异常。

例程2:

Java 代码

   1. public class Thread2 extends Thread{  

   2.     private String who;  

   3.     public void run(){  

   4.         System.out.println(who+":"+this.getName());  

   5.     }  

   6.     public Thread2(String who){  

   7.         super();  

   8.         this.who = who;  

   9.     }  

  10.     public Thread2(String who,String name){  

  11.         super(name);  

  12.         this.who = who;  

  13.     }  

  14.     public static void main(String args[]){  

  15.         Thread2 thread1 = new Thread2("thread1","MyThread1");  

  16.         Thread2 thread2 = new Thread2("thread2");  

  17.         Thread2 thread3 = new Thread2("thread3");  

  18.         thread2.setName("MyThread2");  

  19.         thread1.start();  

  20.         thread2.start();  

  21.         thread3.start();  

  22.     }  

  23. }  

public class Thread2 extends Thread{

    private String who;

    public void run(){

        System.out.println(who+":"+this.getName());

    }

    public Thread2(String who){

        super();

        this.who = who;

    }

    public Thread2(String who,String name){

        super(name);

        this.who = who;

    }

    public static void main(String args[]){

        Thread2 thread1 = new Thread2("thread1","MyThread1");

        Thread2 thread2 = new Thread2("thread2");

        Thread2 thread3 = new Thread2("thread3");

        thread2.setName("MyThread2");

        thread1.start();

        thread2.start();

        thread3.start();

    }

}

程序的运行结果如下:

thread1:MyThread1

thread2:MyThread2

thread3:Thread-1

结果分析:

thread1通过调用了Thread类的public Thread(String name)构造方法来设置线程名称。

thread2通过setName()方法来修改线程名称。

thread3未设置线程名称。

注意:在调用start方法前后都可以使用 setName()方法设置线程名,但在调用start()方法后使用setName()修改线程名称,会产生不确定性,也就是说可能在run()方法执行完后才会去执行setName()方法,此时,如果在run方法中要使用线程名,就会出现虽然调用了setName()方法,但线程名称却未修改的现象。

例程3:

Java 代码

   1. public class TestThread1{  

   2.     public static void main(String args[]){  

   3.         Thread t1 = new Thread3();  

   4.         Thread t2 = new Thread3();  

   5.         t1.start();  

   6.         t2.start();  

   7.     }  

   8. }  

   9. class Thread3 extends Thread{  

  10.     public void run(){  

  11.         for(int i=0;i<10;i++){  

  12.             System.out.println(this.getName()+":"+i);  

  13.         }  

  14.     }  

  15. }  

public class TestThread1{

    public static void main(String args[]){

        Thread t1 = new Thread3();

        Thread t2 = new Thread3();

        t1.start();

        t2.start();

    }

}

class Thread3 extends Thread{

    public void run(){

        for(int i=0;i<10;i++){

            System.out.println(this.getName()+":"+i);

        }

    }

}

程序的运行结果如下:

Thread-0:0

Thread-0:1

Thread-1:0

Thread-0:2

Thread-0:3

Thread-0:4

Thread-1:1

Thread-0:5

Thread-0:6

Thread-1:2

Thread-0:7

Thread-1:3

Thread-0:8

Thread-1:4

Thread-0:9

Thread-1:5

Thread-1:6

Thread-1:7

Thread-1:8

Thread-1:9

例程4:

Java 代码

   1. public class FirstThread extends Thread{  

   2.     private int i;  

   3.     public void run(){  

   4.         for(;i<10;i++){  

   5.             System.out.println(this.getName()+":"+i);  

   6.         }  

   7.     }  

   8.     public static void main(String args[]){  

   9.         for(int i=0;i<10;i++){  

  10.             System.out.println(Thread.currentThread().getName()+":"+i);  

  11.             if(i==5){  

  12.                 new FirstThread().start();  

  13.                 new FirstThread().start();  

  14.             }  

  15.         }  

  16.     }  

  17. }  

public class FirstThread extends Thread{

    private int i;

    public void run(){

        for(;i<10;i++){

            System.out.println(this.getName()+":"+i);

        }

    }

    public static void main(String args[]){

        for(int i=0;i<10;i++){

            System.out.println(Thread.currentThread().getName()+":"+i);

            if(i==5){

                new FirstThread().start();

                new FirstThread().start();

            }

        }

    }

}

程序的运行结果如下:

main:0

main:1

main:2

main:3

main:4

main:5

Thread-0:0

Thread-0:1

Thread-0:2

Thread-1:0

main:6

main:7

Thread-1:1

Thread-1:2

Thread-0:3

Thread-1:3

main:8

Thread-1:4

Thread-0:4

Thread-0:5

Thread-1:5

main:9

Thread-1:6

Thread-1:7

Thread-0:6

Thread-1:8

Thread-0:7

Thread-1:9

Thread-0:8

Thread-0:9

结果分析:

从以上结果可以看出:Thread-0和Thread-1两条线程各自都会输出的i变量,比如存在Thread-0:5和Thread-1:5,因为i是FirstThread类的实例变量,而不是局部变量,而每次创建线程对象都需要创建一个FirstThread对象,所以Thread-0和 Thread-1不能共享该实例属性。因而可以得出以下结论:使用继承Thread类的方法来创建线程类,多条线程之间无法共享线程类的实例变量。

二、实现Runnable接口创建线程类

实现Runnable接口的类必须使用Thread类的实例才能创建线程。通过实现Runnable接口来创建并启动多线程的步骤:

(1)定义Runnable接口的实现类,并实现该接口的run()方法。

(2)创建Runnable实现类的实例,然后将该实例作为参数传入Thread类的构造方法来创建Thread对象。

(3)用线程对象的start()方法来启动该线程。

例程5:

Java 代码

   1. public class MyRunnable implements Runnable{  

   2.     public void run(){  

   3.         System.out.println(Thread.currentThread().getName());  

   4.     }  

   5.     public static void main(String args[]){  

   6.         MyRunnable r1 = new MyRunnable();  

   7.         MyRunnable r2 = new MyRunnable();  

   8.         MyRunnable r3 = new MyRunnable();  

   9.         Thread thread1 = new Thread(r1,"MyThread1");  

  10.         Thread thread2 = new Thread(r2);  

  11.         thread2.setName("MyThread2");  

  12.         Thread thread3 = new Thread(r3);  

  13.         thread1.start();  

  14.         thread2.start();  

  15.         thread3.start();  

  16.     }  

  17. }  

public class MyRunnable implements Runnable{

    public void run(){

        System.out.println(Thread.currentThread().getName());

    }

    public static void main(String args[]){

        MyRunnable r1 = new MyRunnable();

        MyRunnable r2 = new MyRunnable();

        MyRunnable r3 = new MyRunnable();

        Thread thread1 = new Thread(r1,"MyThread1");

        Thread thread2 = new Thread(r2);

        thread2.setName("MyThread2");

        Thread thread3 = new Thread(r3);

        thread1.start();

        thread2.start();

        thread3.start();

    }

}

程序的运行结果如下:

MyThread1

MyThread2

Thread-1

当然,实现Runnable接口的类的对象可以被同时传给多个线程对象。上述程序修改如下:

Java 代码

   1. MyRunnable r1 = new MyRunnable();  

   2. Thread thread1 = new Thread(r1,"MyThread1");  

   3. Thread thread2 = new Thread(r1);  

   4. thread2.setName("MyThread2");  

   5. Thread thread3 = new Thread(r1);  

   6. thread1.start();  

   7. thread2.start();  

   8. thread3.start();  

MyRunnable r1 = new MyRunnable();

Thread thread1 = new Thread(r1,"MyThread1");

Thread thread2 = new Thread(r1);

thread2.setName("MyThread2");

Thread thread3 = new Thread(r1);

thread1.start();

thread2.start();

thread3.start();

运行的结果是类似的。

例程6:

Java 代码

   1. public class TestThread2{  

   2.     public static void main(String args[]){  

   3.         Runnable1 r1 = new Runnable1();  

   4.         Thread t1 = new Thread(r1);  

   5.         Thread t2 = new Thread(r1);  

   6.         t1.start();  

   7.         t2.start();  

   8.     }     

   9. }  

  10. class Runnable1 implements Runnable{  

  11.     public void run(){  

  12.         for(int i=0;i<10;i++){  

  13.             System.out.println(Thread.currentThread().getName()+":"+i);  

  14.         }  

  15.     }  

  16. }  

public class TestThread2{

    public static void main(String args[]){

        Runnable1 r1 = new Runnable1();

        Thread t1 = new Thread(r1);

        Thread t2 = new Thread(r1);

        t1.start();

        t2.start();

    }    

}

class Runnable1 implements Runnable{

    public void run(){

        for(int i=0;i<10;i++){

            System.out.println(Thread.currentThread().getName()+":"+i);

        }

    }

}

程序的运行结果如下:

Thread-0:0

Thread-1:0

Thread-1:1

Thread-0:1

Thread-1:2

Thread-0:2

Thread-1:3

Thread-1:4

Thread-1:5

Thread-0:3

Thread-1:6

Thread-0:4

Thread-1:7

Thread-0:5

Thread-1:8

Thread-0:6

Thread-1:9

Thread-0:7

Thread-0:8

Thread-0:9

例程7:

Java 代码

   1. public class SecondThread implements Runnable{  

   2.     private int i;  

   3.     public void run(){  

   4.         for(;i<10;i++){  

   5.             System.out.println(Thread.currentThread().getName()+":"+i);  

   6.         }  

   7.     }  

   8.     public static void main(String args[]){  

   9.         for(int i=0;i<10;i++){  

  10.             System.out.println(Thread.currentThread().getName()+":"+i);  

  11.             if(i==5){  

  12.                 SecondThread st = new SecondThread();  

  13.                 new Thread(st," 新线程1").start();  

  14.                 new Thread(st," 新线程2").start();  

  15.             }  

  16.         }  

  17.     }  

public class SecondThread implements Runnable{

    private int i;

    public void run(){

        for(;i<10;i++){

            System.out.println(Thread.currentThread().getName()+":"+i);

        }

    }

    public static void main(String args[]){

        for(int i=0;i<10;i++){

            System.out.println(Thread.currentThread().getName()+":"+i);

            if(i==5){

                SecondThread st = new SecondThread();

                new Thread(st,"新线程1").start();

                new Thread(st,"新线程2").start();

            }

        }

    }

    

程序的运行结果如下:

main:0

main:1

main:2

main:3

main:4

main:5

main:6

main:7

新线程2:0

新线程1:0

新线程2:1

main:8

新线程2:3

新线程1:2

新线程2:4

main:9

新线程2:6

新线程2:7

新线程1:5

新线程2:8

新线程1:9

结果分析:

从以上结果可以看出:新线程1和新线程2共享一个SecondThread对象,因此在执行run()方法时两个线程对象操纵的是同一个实例变量 i。所以在执行输出的变量i的值是惟一的,例如新线程2:3、新线程1:2、新线程2:4,不会再出现新线程1:3或者新线程2:1等,且i值在逻辑上也是连续的,即i会从1到9由新线程1和新线程2交替惟一地输出,而实际顺序会不连续。因而可以得出以下结:采用实现Runnable接口的方法来创建线程类,多条线程可以共享同一个线程类(Runnable接口的实现类即target类)的实例属性。

注意:在使用继承Thread类时获得当前线程对象直接使用this就可以了,但是实现Runnable接口时要获得当前线程对象必须使用Thread.currentThread()方法。

若对上述程序作如下修改:

Java 代码

   1. SecondThread st1 = new SecondThread();  

   2. SecondThread st2 = new SecondThread();  

   3. new Thread(st1," 新线程1").start();  

   4. new Thread(st2," 新线程2").start();  

SecondThread st1 = new SecondThread();

SecondThread st2 = new SecondThread();

new Thread(st1,"新线程1").start();

new Thread(st2,"新线程2").start();

程序的运行结果如下:

main:0

main:1

main:2

main:3

main:4

main:5

main:6

main:7

新线程1:0

新线程2:0

新线程2:1

新线程1:1

main:8

main:9

新线程1:2

新线程1:3

新线程1:4

新线程2:2

新线程1:5

新线程2:3

新线程1:6

新线程2:4

新线程1:7

新线程2:5

新线程1:8

新线程2:6

新线程1:9

新线程2:7

新线程2:8

新线程2:9

结果分析:

从以上结果可以看出:新线程1和新线程2分别操纵不同的SecondThread对象的实例变量。

记住:Thread类本身也实现了Runnable接口,因此Thread类及其子类的对象也可以作为target传递给新的线程对象。

三、两种创建线程方式的比较

采用继承Thread类方式:

(1)优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。

(2)缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。

采用实现Runnable接口方式:

(1)优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标(target)对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。

(2)缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。

转自:http://supportopensource.javaeye.com/blog/771786
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: