zoukankan      html  css  js  c++  java
  • 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表达式 创建线程


  • 相关阅读:
    Java I/O的典型使用方式
    搜索--hiho 骑士问题
    编程之美--水王(找出出现超过1/2的数)
    深入理解java虚拟机之类文件结构以及加载
    【转载】Java JVM 运行机制及基本原理
    整数的划分总结(转)
    java静态方法和非静态方法
    mongodb 运行错误总结
    MongoDb windows环境安装,附百度云链接
    JAVA解析Json数据
  • 原文地址:https://www.cnblogs.com/penguin1024/p/11762141.html
Copyright © 2011-2022 走看看