黑马程序员技术交流社区

标题: 线程问题 [打印本页]

作者: wangqing    时间: 2011-11-10 13:38
标题: 线程问题
本帖最后由 wangqing 于 2011-11-27 13:36 编辑

创建线程的两种方法的区别是什么?要详细
作者: 柴永菲    时间: 2011-11-10 13:57
第一种方式:使用Runnable接口创建线程
第二种方式:直接继承Thread类创建对

使用Runnable接口创建线程

1.可以将CPU,代码和数据分开,形成清晰的模型

2.线程体run()方法所在的类可以从其它类中继承一些有用的属性和方法

3.有利于保持程序的设计风格一致

  直接继承Thread类创建对象

1.Thread子类无法再从其它类继承(java语言单继承)。

2.编写简单,run()方法的当前对象就是线程对象,可直接操作。

在实际应用中,几乎都采取第一种方式
作者: 高双武    时间: 2011-11-10 14:07
本帖最后由 wudiisss 于 2011-11-10 14:10 编辑

继承了Thread类则不能继承其他的类,如果一个类即继承了其他的类其中又有的代码需要多线程去执行,这种情况下就需要实现Runnable接口的方式,打破了单继承的局限性

继承Tread:线程代码存放在Thread类的run方法中
实现Runnable:线程代码存放在接口子类的Run方法中
作者: 欧阳文愿    时间: 2011-11-10 14:26
创建新执行线程有两种方法。一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可

以分配并启动该子类的实例。例如,计算大于某一规定值的质数的线程可以写成:



--------------------------------------------------------------------------------

     class PrimeThread extends Thread {
         long minPrime;
         PrimeThread(long minPrime) {
             this.minPrime = minPrime;
         }

         public void run() {
             // compute primes larger than minPrime
              . . .
         }
     }

--------------------------------------------------------------------------------

然后,下列代码会创建并启动一个线程:


     PrimeThread p = new PrimeThread(143);
     p.start();
创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建

Thread 时作为一个参数来传递并启动。采用这种风格的同一个例子如下所示:



--------------------------------------------------------------------------------

     class PrimeRun implements Runnable {
         long minPrime;
         PrimeRun(long minPrime) {
             this.minPrime = minPrime;
         }

         public void run() {
             // compute primes larger than minPrime
              . . .
         }
     }

--------------------------------------------------------------------------------

然后,下列代码会创建并启动一个线程:


     PrimeRun p = new PrimeRun(143);
     new Thread(p).start();
每个线程都有一个标识名,多个线程可以同名。如果线程创建时没有指定标识名,就会为其生成一个新名称。

Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。
设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。所以要将Rannable接口的子类对象传递给Thread

,Thread 类可以实现 Runnable接口的全部抽象方法。
另外,Runnable 为非 Thread 子类的类提供了一种激活方式。通过实例化某个 Thread 实例并将自身作为运行目标,就

可以运行实现 Runnable 的类而无需创建 Thread 的子类。大多数情况下,如果只想重写 run() 方法,而不重写其他

Thread 方法,那么应使用 Runnable 接口。这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应为该类

创建子类。
大部分情况下俩种方法都可以,另外,在处理共享数据的时候实现Runnable接口,继承Thread类在处理共享数据时不支持。

作者: 张翼    时间: 2011-11-10 15:11
第一种:
写个类,然后继承Thread,接着改写run方法,线程所要运行的程序代码,就是run这个方法所要运行的程序代码
例子:
  public class hello1 extends Thread
{
    String name;
   pulic hello1(String n)
{
     name=n;
}
public void run()
{
   for(int i=1;i<=10;i++)
     System.out.println(name+"hello"+i):
}
}
第二种,通过实现Runnable 这个接口实现,然后一样去实现run 方法
public class hello2 implements Runnable
{
   String name;
   public hello2(String n)
   {
       name=n;
  }
   public void run()
{
    for(int i=1;i<=10;i++)
     System.out.println(name+"hello"+i);
  }
}
但是一般i情况下使用第二种方式:1:比较符合面向对象设计的精神和架构,接口的作用是让类附加上一些功能,但是并不会改变它原本的集成架构,所以在设计一个类的时候,它本来就有自己的架构和应有的功能;
2,Java类只能单一继承,但可以实现多个接口,如果继承了Thread,就无法再去继承别的类了,就像Java Applet类,如果它想要有线程的功能时,就没办法再继承Thread类。
3,程序的一致性,在开发程序时,编写程序代码最好有共同的风格,如果有的类继承了Thread,有的类实现了Runnable几口,这样不是很统一。


作者: byronsong    时间: 2011-11-10 15:23
创建线程的第一种方式:
继承Thread类。
步骤:
1,定义一个Thread类的子类。
2,复写Thread类中的run方法。将需要线程运行的代码存储到该run方法中。
        run方法的唯一功能是:存储线程要运行的代码。
3,创建Thread类的子类对象。创建线程。
4,调用Thread类中的start方法开启线程并运行子类的run方法。
*/
class Demo extends Thread
{
        public void run()
        {
                for(int x=0;x<100; x++)
                {
                        System.out.println("zzzzzzz----"+x);
                }
        }
}

class  ThreadDemo
{
        public static void main(String[] args)
        {
               

                //Thread t = new Thread();//创建了一个线程对象。
                /*
                注意:线程的创建和运行是两个。运行是通过start方法完成的。
                */
                //t.start();//开启线程执行。
                /*

                发现start方法有两个动作。
                1,开启线程,让线程执行。开启线程的目的其实就是为了让这条执行路径去执行指定代码。
                2,告诉jvm调用这个线程的run方法。 猜想,run方法,是不是就意味着内部封装了线程要执行的代码呢?
                发现run方法没有执行任何动作就返回了。

                注意:我们开启线程,是为了让线程去执行我们指定的代码。
                所以Thread类就给我们提供了一个线程要运行的代码存放的位置。
                但是要运行什么代码Thread并不知道。
                所以我们需要将要运行的代码存储到run方法里面。
                那不是就沿袭父类中的功能,定义子类特有的内容。
                就是覆盖调用父类的方法即可。

                //创建线程。
                Demo d = new Demo();//创建Thread类的子类对象,也是创建线程。
                d.start();
//                d.run();//和start有区别吗?调用run就只有一个线程main在运行,而且run中的代码都由main线程运行的。
                                                //创建的新线程根本就没有运行,所以只有主线程在运行。

                                //start是先开启线程,然后让新的线程去运行自己的run方法。

               
                                for(int x=0;x<100; x++)
                {
                        System.out.println("aaaaa.."+x);
                }
               
        }
}
线程创建的第二种方式:
实现Runnable接口。
步骤:
1,定义一个Runnable接口的子类。
2,覆盖Runnable接口的run方法。
3,通过Thread类创建线程对象。
4,将实现Runnable接口的子类对象作为参数传递给Thread类的构造函数。
        为什么要这么做呢?
        因为要告诉线程对象要运行哪个run方法。
        现在线程要执行的代码都存储到了Runnable接口的子类对象中。
        那么线程要运行这个run方法。必须要明确这个run方法所属的对象。
        所以将该对象传递给Thread构造函数。这样线程对象就可以去执行指定的run方法。
5,通过线程对象的start开启线程并执行。
这种方式的好处:避免了单继承的局限性。
所以通常情况下,创建线程,都使用实现Runnable接口的方式。

class Demo implements Runnable
{
        public void run()
        {
                for(int x=0; x<100; x++)
                {
                        System.out.println(Thread.currentThread().getName()+"....qqqqqq....."+x);
                }
        }
}



class  ThreadDemo3
{
        public static void main(String[] args)
        {

                Demo d = new Demo();

                Thread t1 = new Thread(d);//创建线程对象。
                Thread t2 = new Thread(d);

                t1.start();//开启两个线程。
                t2.start();

                /*
                创建了两个线程对象,都用start开启了,但是没有结果。
                那是因为,start方法开启线程,并执行了线程的run方法。

                */

        }
}




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2