黑马程序员技术交流社区

标题: 创建多线程的两种方式 [打印本页]

作者: anyway1919    时间: 2015-9-17 12:05
标题: 创建多线程的两种方式
API中告诉我们创建线程有2种方式:
第一种:
1、定义一个类继承Thread
2、子类复写Thread类中的run方法
3、创建子类对象(子类就是一个线程类)
4、启动子类对象
  1. /*
  2. * 演示创建线程的第一种方式
  3. */
  4. //定义子类,继承Thread
  5. class Demo extends Thread{
  6.        
  7.         //复写run方法
  8.         public void run(){
  9.                
  10.                 for( int i=0;i<20;i++ ){
  11.                         System.out.println("demo run i = "+i);
  12.                 }
  13.         }
  14. }

  15. public class ThreadDemo {
  16.         public static void main(String[] args) {
  17.                
  18.                 //创建子类对象
  19.                 Demo d = new Demo();
  20.                 //启动线程
  21.                 d.start();

  22.                 for( int i=0;i<20;i++ ){
  23.                         System.out.println("main i = "+i);
  24.                 }
  25.                
  26.         }
  27. }
复制代码


分析:
1)、为什么要继承Thread类?
线程是计算机中程序运行的一个独立单元,这个单元Java使用Thread类进行了描述。现在我们需要自己使用线程,执行我们自己的某些代码。
Thread类是Java中提供的原生的类,而我们具体需要操作线程时,不能直接去使用Thread,如果直接去使用的Thread,导致原生的Thread类无法知道我们后期真正需要让线程执行的代码。
API中告诉我们需要自己定义一个类继承Thread,我们自己的类继承了Thread那么自己的类就变成线程类,就继承到Thread类中的所有功能,我们自己的类就可以去使用Thread类中定义的所有操作线程的功能。

继承Thread类的目的就是让自己的类变成线程类。可以去操作线程。
2)、线程是计算机中程序运行的一个独立单元,这个单元Java使用Thread类进行了描述。现在我们需要自己使用线程,执行我们自己的某些代码。
Thread类是Java中提供的原生的类,而我们具体需要操作线程时,不能直接去使用Thread,如果直接去使用的Thread,导致原生的Thread类无法知道我们后期真正需要让线程执行的代码。
API中告诉我们需要自己定义一个类继承Thread,我们自己的类继承了Thread那么自己的类就变成线程类,就继承到Thread类中的所有功能,我们自己的类就可以去使用Thread类中定义的所有操作线程的功能。

继承Thread类的目的就是让自己的类变成线程类。可以去操作线程。
2)、为什么要复写run方法
我们开启线程的目的是让多部分代码同时运行,让线程去执行我们自己的某些代码,而这些代码需要交给线程运行,那么我们就必须按照线程运行时会调用的某些固定的功能。
当我们调用start方法的时候,JVM在底层会自动的调用run方法,而run方法中的代码就会被某个线程去执行。
而我们开启线程的目的就是希望线程执行某些代码,也就是只要大家把需要线程执行的代码书写在run方法中,一旦开启线程,run方法会自动的运行  过,那么就会 导致 书写在run方法中的所有代码会被当前某个线程去调用执行。
复写run方法的目的:就是希望在run方法中书写线程要执行的那么代码。
线程要执行的代码:称为线程的任务。
3)为什么不直接调用run方法,而调用start方法
如果我们直接调用run方法,这时虽然有线程对象,但是并没有让线程真正开启,而不开启线程,直接通过线程对象调用run方法,这个和我们以前学习的对象调用普通方法没有任何区别,这些调用的功能都会在主线程所在的区域中运行。

如果我们有了线程对象,希望线程可以独立去运行,只能手动调用Thread类提供的start方法,才能在栈内存中开启一个新的执行通道(路径),这样才能保证run方法会被加载到新的执行路径中去运行。

开启线程的第二种方式
1、定义一个类 实现 Runnable 接口
2、实现接口中的run方法
3、创建实现类的对象
4、创建Thread对象,把实现类对象作为参数传递
5、Thread对象开启线程
  1. /*
  2. * 演示创建线程的第二种方式
  3. */
  4. class Demo2 implements Runnable{
  5.        
  6.         //实现run方法
  7.         public void run() {
  8.                 for( int i=0;i<20;i++ ){
  9.                         System.out.println("demo2 run i = "+i);
  10.                 }
  11.         }
  12. }
  13. public class ThreadDemo2 {
  14.         public static void main(String[] args) {
  15.                
  16.                 //创建实现类的对象
  17.                 Demo2 d  = new Demo2();
  18.                
  19.                 //创建Thread对象
  20.                 Thread t = new  Thread( d );
  21.                
  22.                 //开启线程
  23.                 t.start();
  24.                
  25.                 for( int i=0;i<20;i++ ){
  26.                         System.out.println("main i = "+i);
  27.                 }
  28.         }
  29. }
复制代码

分析:实现Runnable的原理:
1)、Java中继承的局限性
Java只支持单继承,不支持多继承。如果一个类已经有父类了,但这个类中有部分代码需要多线程操作,这时我们就没有办法再让这个类去继承Thread。也就是Java中提供的第一种方式就无法使用。导致没有办法去操作多线程了。

Thread类是描述线程,Thread类就应该只定义如何去操作线程的功能,在Thread中提供了一个run方法,而这个run方法是专门用来明确线程要执行的任务的方法。于是就run方法从Thread类中抽离出来,专门定义了一个接口,后期真正在开发中,如果要明确线程的任务,找对应的接口,如果要操作线程就直接找Thread。
2)、Java中提供的接口的作用
           1、 给事物体现添加(增加)扩展功能。
           2、给事物双方定义规则。
Runnable接口它其实是在定义线程中操作任务的一个规则。线程是可以操作任务的,而任务是需要后来程序书写和明确的。只有我们明确的任务符合Runnable接口的规范,那么Thread才能去真正调用run方法。
3)、其他的技术问题:
1、我们在创建Thread类的时候,其实只是明确了线程对象
2、书写的实现了Runnable接口的类,相当于明确了线程要执行的任务类,当我们创建了实现类对象,就相当于明确了线程要执行的任务对象。
3、需要在创建Thread对象的时候,把线程的任务对象传递给Thread,这样就让线程对象和任务对象之间产生了关系。
4、我们调用Thread的start方法的时候,就会根据对应的关系调用到其中的run方法。

作者: Jared    时间: 2015-9-26 14:35
进来学习一下
作者: phantom33    时间: 2015-9-26 16:24
进来学习一下
作者: lostyou    时间: 2015-9-26 19:01
好仔细 这个学习态度可以的




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