02-线程的三种创建方式

java.lang.Thread类用于创建线程对象,java虚拟机允许同时运行多个线程。
 
在Java中,实现多线程操作有三种方式:
1). 自定义类继承 Thread 并重写run()方法,调用start()方法启动线程。
2). 自定义类实现 Runnable 接口; 并重写run()方法,调用start()方法启动线程。
3). 自定义类实现 Callable 接口.
 

Thread类的方法

构造方法:
Thread( ) - 使用无参的形式构造线程对象。
Thread(String name) - 使用参数指定的名称来构造线程对象。
Thread(Runnable target) - 根据参数指定的接口引用来构造线程对象。
Thread(Runnable target, String name) - 根据接口引用和线程名称共同构造对象。
 

普通方法:

void run( )      - 若使用Runnable接口作为参数创建了线程对象,则调用该接口中被重写以后的run()方法;否则该方法什么也不做就直接返回。

void start( )    - 使得线程启动起来,java虚拟机会自动调用该线程的run()方法。

 

 

 

 


 

1.继承Thread

 

//1) 定义类继承Thread
public class SubThread extends Thread {
//2)重写run()方法, run()方法体中的代码就是子线程要执行的代码 @Override public void run() {
//在子线程,打印100行字符串 for(int i = 1; i<101; i++){ System.out.println("sub thread : " + i); } } }

 

 

 测试

package com.mmonkey1024;

public class Test {

    public static void main(String[] args) {
        
        // SubThread subThread = new SubThread();
        
        
        // 形成多态
         Thread thread = new SubThread();
         
         // 创建线程
         thread.start();
         
         
         //重点: 调用run()也会执行,但是这样做 并没有 开启一个线程!!!
         // thread.run();
         
         
         for(int i = 1; i <= 5; i++) {
             System.out.println("执行主线程中的循环: "+i);
             
         }
    }

}

 

结果:

执行主线程中的循环: 1
执行主线程中的循环: 2
子线程中的循环: 1
执行主线程中的循环: 3
子线程中的循环: 2
执行主线程中的循环: 4
子线程中的循环: 3
子线程中的循环: 4
子线程中的循环: 5
执行主线程中的循环: 5

 

 

 

 


 

2.实现Runnable 接口

 实现Runnable 接口 再重写run()方法

package com.mmonkey1024;
//1) 定义Runnable接口的实现类
public class Prime implements Runnable {
    
    //2)重写run()方法, run方法体就是用户线程执行的代码
    @Override    
    public void run() {
        for(int i = 1;  i<=10; i++){
            System.out.println("子线程  : " + i);
        }

    }

}

 

测试类

package com.mmonkey1024;
//1) 定义Runnable接口的实现类
public class Prime implements Runnable {
    
    //2)重写run()方法, run方法体就是用户线程执行的代码
    @Override    
    public void run() {
        for(int i = 1;  i<=10; i++){
            System.out.println("子线程  : " + i);
        }

    }

}

或者 使用匿名内部类

package com.mmonkey1024;
public class Test{ 
    

    public static void main(String[] args) {
        
        //在调用方法时,实参是接口匿名内部类对象
        Thread t1 = new Thread(new Runnable() {
            
            //在匿名内部类中重写接口抽象方法
            @Override
            public void run() {
                //指定子线程要执行的代码
                for(int i = 1;  i<=100; i++){
                    System.out.println("t1线程  : " + i);
                }
            }
        });
        t1.start();  // 开启t1线程
        
        
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                //指定子线程要执行的代码
                for(int i = 1;  i<=100; i++){
                    System.out.println("t2线程  : " + i);
                }
            }
        });
        t2.start();  // 开启t2线程

        
        
        // main线程
        for (int i = 1; i <= 100; i++) {
            System.out.println("main线程   " + i);
        }
    }
    
    
}

 

 

 

 

 


 

3.实现Callable 接口

 //Callable接口中的call()有返回值,  通过Callable泛型 指定返回值的类型
//Runnable接口中的run()方法没有返回值 , Callable接口的call()有返回值

 

package com.mmonkey1025;

import java.util.Random;
import java.util.concurrent.Callable;

//1) 定义类实现Callable接口
public class Prime implements Callable<Integer> {
    
    //2)重写抽象方法call()方法  
    @Override
    public Integer call() throws Exception {
        
        int  result = new Random().nextInt(100);
        
        System.out.println("执行子线程, 完成某个计算,  结果为: " + result);
        
        return result;
    }

}

 

 

 

测试类

 

package com.mmonkey1025;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Test {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        
        //1.创建线程对象
        Prime prime = new Prime() ;        //创建Callable接口实现类对象    
        
        FutureTask<Integer> task = new FutureTask<>(prime);
        
        //FutureTask实现了RunnableFuture<V>接口,该接口继承了Runnable接口, FutureTask类就是Runnable接口实现类
        Thread t3 = new Thread(task);
        
        //2.开启新的线程
        t3.start();

        //
        System.out.println("当前线程是main线程,可以获得子线程的执行结果:");
        System.out.println("result=" + task.get());
        
    }
}

 

 

 

 


 

分析一下::

                                               Thread  t  = new  Thread( );    // 创建Thread类型的引用 指向 Thread 自己的对象:只能调用本类内部的run()方法

                                    t.run( );

                                    t.start( );

 

                     //若希望 调用上面重写之后的run()方法,则需要使用接口引用作为参数的方式

                           // 接口类型的引用 指向了实现类的对象,形成了多态

                                 Thread  t  = new  Thread(  new SubRunnable() );

                                  t.start( );    // 通过Thread类型的引用,调用start()方法,运行阶段会自动调用实现类中重写后的run()方法

 


 

 三,线程的原理分析

执行main()方法的线程叫做主线程,调用start()方法出现出来的线程叫做 新 / 子线程
对于start()方法之前的代码来说,只会被主线程自己执行一遍,而start( )方法一旦调用成功,该进程中的线程瞬间由1个变成了2个;
其中主线程继续执行 start( )方法之后的语句块,而新启动的子线程去执行run()方法中的语句块。
当run()方法的方法体执行完毕时,子线程结束; 当main()方法的方法体执行完毕时,主线程结束;
主线程和子线程各自独立运行,没有执行 的先后次序,取决于操作系统的调度算法。
 
 
 
四,三种实现多线程的方式在实际应用中的区别:
 
经验:
目前创建线程的方式有三种:
第一种 继 承的方式 代码相对简单但不支持多继承;
第二种 实现接口的方式代码相对复杂但可以多实现并单继承,因此以后开发中推荐使用第二种方式。

 

 


 

扩展:使用匿名内部类 的技术来实现上述前2种创建 和 启动线程的方式:

4.使用匿名内部类 创建线程

 

 

1. 将继承的方式改为 匿名内部类的策略实现

 

 

public class NoNameStartTest {
    
    
    public static void main(String[] args) {
        
        // 1. 将继承的方式改为 匿名内部类的策略实现
        new Thread() {

            @Override
            public void run() { 
                System.out.println("十月秋风天气凉,可惜没钱买衣裳.....");
            }
        }.start();       // 开启线程
        
    }
}

 

 

 

结果:

 

十月秋风天气凉,可惜没钱买衣裳.....

 

 

 

 

2.将接口的方式改为 匿名内部类的策略实现

 

package com.monkey1031;

public class NoNameStartTest {
    
    
    public static void main(String[] args) {
        
        // 2. 将接口的方式改为 匿名内部类的策略实现
        
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                System.out.println("十月秋风天气寒,可惜没钱买衣裳");
                
            }
        }).start();    // 开启线程
    }
}

 

 

 

结果:

 

十月秋风天气寒,可惜没钱买衣裳

 


 

5.使用lambda表达式 创建线程

 

 

 

 


 

 

 

 

 

posted @ 2019-10-29 22:51  小茅棚  阅读(175)  评论(0编辑  收藏  举报