zoukankan      html  css  js  c++  java
  • 10分钟学会java中创建多线程的四种方式

    java中创建多线程的四种方式,分别是继承Thread类,实现Runnable接口,jdk5.0以后又增加了两种方式:实现Callable接口和使用线程池。在这里我将这四种方式进行总结。

    继承Thread类

    步骤

    1. 定义一个类继承Thread类
    2. 重写run方法:里面写线程要运行的任务代码
    3. 创建Thread子类对象
    4. 调用start方法:开启线程并调用run方法

    代码

    package thread_demo;
    
    public class ThreadDemo {
        public static void main(String[] args) {
    
            // 创建Thread的子类对象,创建线程。
            Demo d1  = new Demo("旺财");
            Demo d2  = new Demo("小强");
    //        d1.run();
    //        d2.run();
            d1.start(); //开启线程,编号从0开始;
            d2.start();
    
            for(int i=0;i<10;i++){
                System.out.println("主函数:"+Thread.currentThread().getName()+"...i="+i);
            }
        }
    }
    
    class Demo extends Thread{ // 定义一个类继承Thread
    
        private String name;
        Demo(String name){
            this.name = name;
        }
    
        // 覆盖Thread类中的run方法:run方法中定义就是线程要运行的任务代码
        public void run(){
            show();
        }
    
        public void show(){
            for(int i=0;i<10;i++){    System.out.println(name+":"+Thread.currentThread().getName()+"...i="+i);
            }
        }
    }
    

    结果输出

    主函数:main...i=0
    主函数:main...i=1
    主函数:main...i=2
    主函数:main...i=3
    主函数:main...i=4
    主函数:main...i=5
    主函数:main...i=6
    主函数:main...i=7
    主函数:main...i=8
    主函数:main...i=9
    旺财:Thread-0...i=0
    旺财:Thread-0...i=1
    旺财:Thread-0...i=2
    旺财:Thread-0...i=3
    旺财:Thread-0...i=4
    旺财:Thread-0...i=5
    旺财:Thread-0...i=6
    旺财:Thread-0...i=7
    旺财:Thread-0...i=8
    旺财:Thread-0...i=9
    小强:Thread-1...i=0
    小强:Thread-1...i=1
    小强:Thread-1...i=2
    小强:Thread-1...i=3
    小强:Thread-1...i=4
    小强:Thread-1...i=5
    小强:Thread-1...i=6
    小强:Thread-1...i=7
    小强:Thread-1...i=8
    小强:Thread-1...i=9
    

    实现Runnable接口

    步骤

    1. 定义子类实现Runnable接口
    2. 子类中重写run方法:将线程的任务代码封装到run方法中;
    3. 创建实现子类的对象
    4. 通过Thread类创建线程对象,并将该子类对象作为构造器的参数进行传递
    5. 调用Thread类的start方法

    代码

    package thread_demo;
    
    public class ThreadDemo2 {
        public static void main(String[] args) {
    
            Demo2 d = new Demo2();//3.创建实现类对象
    
            Thread t1 = new Thread(d); // 4.通过Thread类创建线程对象
            t1.start(); // 5. 调用start方法
    
        }
    }
    
    class Demo2 implements Runnable //1. 通过接口的形式扩展Demo类的功能
    {
        // 2. 覆盖run方法;
        public void run(){
            show();
        }
        public void show(){
            for(int i=0;i<10;i++){
                System.out.println(Thread.currentThread().getName()+"...i="+i);
            }
        }
    }
    

    结果输出:

    Thread-0...i=0
    Thread-0...i=1
    Thread-0...i=2
    Thread-0...i=3
    Thread-0...i=4
    Thread-0...i=5
    Thread-0...i=6
    Thread-0...i=7
    Thread-0...i=8
    Thread-0...i=9
    

    实现Callable接口

    步骤

    1. 创建Callable的实现类:class XxxXxx implements Callable
    2. 重写call方法,将线程的任务代码封装到call方法中:public Object call() throws Exception{}
    3. 创建Callable接口实现子类的对象;
    4. 创建FutureTask的对象,将此Callable接口实现类的对象作为构造器的参数进行传递: FutureTask futureTask = new FutureTask(numThread);
    5. 创建Thread对象,并调用start()。将FutureTask的对象作为参数传递到Thread类的构造器中:new Thread(futureTask).start();
    6. 获取Callable中call方法的返回值。 get() 返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值

    代码

    package thread_demo;
    
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    // 1. 创建一个实现Callable的实现类
    class NumThread implements Callable {
        // 2. 实现call方法,将此线程需要执行的操作声明在call中
        @Override
        public Object call() throws Exception{
            //遍历1-100打印出偶数之和
            int sum = 0;
            for(int i = 1; i <= 100; i++){
                if((i & 1) == 0){ // i%2 == 0
                    System.out.println(i);
                    sum += i;
                }
            }
            return sum;
        }
     
    }
    
    public class NumThreadTest {
        public static void main(String[] args) {
            // 3. 创建Callable接口实现类的对象;
            NumThread numThread = new NumThread();
            // 4. 将此Callable接口实现类的对象传递到FutureTask构造器中,创建FutureTask的对象;
            FutureTask futureTask = new FutureTask(numThread);
            // 5. 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
            new Thread(futureTask).start();
            try {
                // 6. 获取Callable中call方法的返回值
                // get() 返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值
                Object sum = futureTask.get();
                System.out.println("总和是:"+sum);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("异常");
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
    
        }
    }
    

    结果输出:

    2
    4
    6
    8
    ...
    98
    100
    总和是:2550
    

    使用线程池

    步骤

    1. 提供指定线程数量的线程池;借助于Executors中的方法;
    2. 执行指定的线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
      1. Runnable:service.execute(子类对象)
      2. Callable:service.submit(子类对象)
    3. 关闭连接池

    注意: 子类对象都可以写成匿名对象

    代码

    package thread_demo;
    
    import java.util.concurrent.*;
    
    /**
     * @ClassName: ThreadDemo2
     * @author: benjamin
     * @version: 1.0
     * @description: TODO
     * @createTime: 2019/04/18/09:32
     */
    
    public class ThreadDemo2 {
        public static void main(String[] args) {
    
            //1. 提供指定线程数量的线程池;
            ExecutorService service = Executors.newFixedThreadPool(10);
            //2. 执行指定的线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
    //        service.execute(new NumThreadRun()); //适用于Rallable
            Future future = service.submit(new NumThreadCall());//适用于Callable
            try {
                Thread.sleep(5000);// 先延迟5秒
                System.out.println("输出结果"+future.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            //3. 关闭连接池
            service.shutdown();
        }
    }
    
    
    class NumThreadRun implements Runnable {
        // 2. 实现run方法,将次线程需要执行的操作声明在run中
        @Override
        public void run() {
            int sum = 0;
            for (int i = 1; i <= 100; i++) {
                if (i % 2 == 0) {
                    System.out.println(i+Thread.currentThread().getName());
                    sum += i;
                }
            }
            System.out.println("偶数之和="+sum);
        }
    }
    
    // 1. 定义Callable的实现类
    class NumThreadCall implements Callable {
        // 2. 重写call方法,将此线程需要执行的操作声明在call中
        @Override
        public Object call() throws Exception {
            //遍历1-100打印出奇数之和
            int sum = 0;
            for (int i = 1; i <= 100; i++) {
                if ((i & 1) != 0) {
                    System.out.println(i+Thread.currentThread().getName());
                    sum += i;
                }
            }
            return sum;
        }
    }
    

    总结

    继承Thread类和Runnable接口的比较

    Thread类实现了Runnable接口public class Thread implements Runnable

    都需要重写run()

    Thread中的start和run方法的区别

    调用run方法和创建对象调用方法没有区别;由JVM调用,什么时候调用,执行的过程控制都有操作系统的CPU调度决定

    线程中的start方法会创建并启动一个线程;一个线程对象只能调用一次start()方法启动,如果重复调用了,则将抛出异常 IllegalThreadStateException

    Callable比Runnable的优势

    call()可以有返回值,返回值通过 FutureTask 进行封装。通过future的get方法获取返回值
    call()可以抛出异常,被外面的操作捕获,获取异常的信息;
    Callable支持泛型

    线程池好处

    提高响应速度(减少了创建新线程的时间)
    降低资源消耗(重复利用线程池中的线程,不需要每次都创建);
    便于线程管理

  • 相关阅读:
    sqlite android
    cocos2dx 2.1.3 使用json
    cocos2dandroid 自动缩放、高清显示
    cocos2dx HttpClient
    coco2dx 2.1.3 之 使用网络请求
    facebook on android
    项目运行出错怎么办?
    Bug应对策略 本文系转
    从网页中导入Excel
    ASP.NET HTTP运行时组成详解[转帖]
  • 原文地址:https://www.cnblogs.com/benjieqiang/p/11376076.html
Copyright © 2011-2022 走看看