zoukankan      html  css  js  c++  java
  • 8.1.多线程创建的4种方法

    JDK1.5之前创建新执行线程有两种方法:

    方式1:继承Thread类 :

    1) 定义子类继承Thread类。
    2) 子类中重写Thread类中的run方法。
    3) 创建Thread子类对象,即创建了线程对象。
    4) 调用线程对象start方法:启动线程,调用run方法。
    //1.创建一个继承于Thread()类的子类
    class MyThread extends Thread{
        //        2 重写Thread类的run()方法
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if(i%2==0){
                    System.out.println(i);
                }
            }
        }
    }
    
    
    public static void main(String[] args) {
    //        3 创建Thread类的子类的对象
            MyThread myThread=new MyThread();
    //        4 通过此对象调用start()方法
            myThread.start();//1 启动当前线程 2 调用当前线程的run()方法
            //问题一:我们不能通过对象调用run()方法的方式启动线程
    //        myThread.run();//如果这样的话,就没有启动线程,只是调用了方法
    
            //问题二:再启动一个线程,遍历100以内的偶数,不可以
            //还让已经start()的线程去执行start()方法,会报IllegalThreadStateException
    //        myThread.start();
        }
    

    方式二:实现Runnable接口

    1) 定义子类,实现Runnable接口。
    2) 子类中重写Runnable接口中的run方法。
    3) 通过Thread类含参构造器创建线程对象。
    4) 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
    5) 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法
    
    //1.创建一个实现了Runnable接口的类
    class MThread implements Runnable{
    //2.实现类去实现Runnable中的抽象方法:run()
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if(i%2==0){
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }
            }
        }
    }
    
    public static void main(String[] args) {
    //        3.创建实现类的对象
            MThread mThread=new MThread();
    //        4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
            Thread t1 = new Thread(mThread);//将mThread赋值给target
            t1.setName("线程1");
    //        5.通过Thread()类的对象调用start()
            //1启动线程 2 调用当前线程的run()--》调用了Runnable类型的target的run()
            t1.start();
        }
    

    比较创建线程的两种方式:

     开发中:优先选择:实现Runnable接口的方式
     原因:1.实现的方式没有类的单继承的局限性
    2.实现的方式更适合来处理多个线程有共享数据的情况。
    
     联系:public class Thread implements Runnable-->Thread类也实现了Runnable接口
     相同点:两种方式都需要重写run()方法,将线程要执行的逻辑声明在run()方法中。
    区别
    继承Thread:线程代码存放Thread子类run方法中。
    实现Runnable:线程代码存在接口的子类的run方法。
    

    JDK5.0 新增线程创建两种方式:

    新增方式一:实现Callable 接口

    1.创建一个实现Callable的实现类
    2.实现call方法,将此线程需要执行的操作声明在call()中
    3.创建Callable接口实现类的对象
    4.将此Callable接口实现类的对象作为参数传递到FutureTask构成器中,创建FutureTask的对象
    5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
    
    //1.创建一个实现Callable的实现类
    class NumThread implements Callable{
    //2.实现call方法,将此线程需要执行的操作声明在call()中
        @Override
        public Object call() throws Exception {
            int sum=0;
            for (int i = 1; i <= 100; i++) {
                if(i%2==0){
                    System.out.println(i);
                    sum += i;
                }
            }
            return sum;
        }
    }
    
    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();//FutureTask类也实现了Runnable接口
            try {
                //6.获取Callable中的call方法的返回值
                //get()方法的返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。
                Object  sum = futureTask.get();
                System.out.println("总和为:"+sum);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    
    

    如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大?

    1.call()可以有返回值的
    2.call()可以抛出异常,被外面的操作捕获,获取异常的信息
    3.Callable是支持泛型的
    

    新增方式二:使用线程池

    corePoolSize:核心池的大小
    maximumPoolSize:最大线程数
    keepAliveTime:线程没有任务时最多保持多长时间后会终止
    1.提供指定线程数量的线程池
    2.执行指定线程的操作,需要提供实现Runnable接口或者Callable接口实现类的对象
    3.关闭线程池
    
    class NumberThread implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if(i%2==0){
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }
            }
        }
    }
    
    public static void main(String[] args) {
            //1.提供指定线程数量的线程池
            ExecutorService service = Executors.newFixedThreadPool(10);
            ThreadPoolExecutor service1= (ThreadPoolExecutor) service;
            //设置线程池的属性
    //        System.out.println(service.getClass());
            service1.setCorePoolSize(15);
    //        service1.setKeepAliveTime();
            //2.执行指定线程的操作,需要提供实现Runnable接口或者Callable接口实现类的对象
            service.execute(new NumberThread());//适合使用于Runnable
            service.execute(new NumberThread1());//适合使用于Runnable
    //        service.submit(Callable callable);//适合使用于Callable
    
            service.shutdown();//3.关闭线程池
        }
    

    好处:

    提高响应速度(减少了创建新线程的时间)
    降低资源消耗(重复利用线程池中线程,不需要每次都创建)
    便于线程管理
    
  • 相关阅读:
    在Windows系统下搭建ELK日志分析平台
    ELK安装成windows服务
    ElasticSearch NEST笔记
    ElasticSearch5.0——IK词库加载
    ElasticSearch速学
    搜索引擎选择: Elasticsearch与Solr
    windows文件名太长无法删除的解决办法
    Elasticsearch(八)【NEST高级客户端--Mapping映射】
    elasticsearch 配置详解
    Elasticsearch(八)【NEST高级客户端--分析器】
  • 原文地址:https://www.cnblogs.com/2719610441qqcom/p/14666906.html
Copyright © 2011-2022 走看看