java多线程

java中定义线程类方法:

  1. 继承Thread类,实现run()方法;
  2. 定义类实现Runable接口;@Override 覆盖 run()方法;
  3. 定义类实现Callable接口,并与Future、线程池结合使用;

Java 线程:

  1. run() 方法是多线程程序的一个约定。所有的多线程执行代码都在run方法里面。Thread类实际上也是实现了Runnable接口的类。
  2. thread.start() 方法的调用后并不是立即执行多线程代码,而是使得该线程变为可运行态(Runnable),(参考线程状态转换)什么时候运行是由操作系统决定的;

常用函数:

       sleep(): 强迫一个线程睡眠N毫秒。 
  isAlive(): 判断一个线程是否存活。 
  join(): 等待线程终止。 
  activeCount(): 程序中活跃的线程数。 
  enumerate(): 枚举程序中的线程。 
       currentThread(): 得到当前线程。 
  isDaemon(): 一个线程是否为守护线程。 
  setDaemon(): 设置一个线程为守护线程。(用户线程和守护线程的区别在于,是否等待主线程依赖于主线程结束而结束) 
  setName(): 为线程设置一个名称。 
  wait(): 强迫一个线程等待。 
  notify(): 通知一个线程继续运行。 
  setPriority(): 设置一个线程的优先级。
 


java中定义线程池方法:import java.util.concurrent.Executors; 创建线程池,返回 ExecutorService 对象;

import java.util.concurrent.*;

    @Test
    public void testNewThreadPool(){
        //5种创建线程池的方法
        ExecutorService service  = Executors.newCachedThreadPool();     //缓存型
        ExecutorService service1 = Executors.newSingleThreadExecutor(); //单例型
        ExecutorService service2 = Executors.newWorkStealingPool(10);   //CPU数量型
        ExecutorService service3 = Executors.newFixedThreadPool(10);    //固定型
        ExecutorService service4 = Executors.newScheduledThreadPool(10);//调度型

        //生产线程的工厂类,可以定义线程名,优先级等。
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
        //自定义线程池:大小、最大、延时、执行队列,指定名称,策略               //自定义型
        ExecutorService service5 = new ThreadPoolExecutor(5, 200,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.CallerRunsPolicy());


        service5.submit(new Runnable() {
            @Override
            public void run() {
                while(true){
                    System.out.println("hello world !");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        System.out.println(" ===> main Thread execute here ! " );
        
    }
//结果先执行main Thread,等待1秒后执行线程池,hello world

Java创建任务:任务分为两种:一种是有返回值的( callable ),一种是没有返回值的( runnable ),因此任务就是实现了callable或runnable的类实例,提交给线程池后,什么时间运行,执行顺序都由线程池来管理;

  • 无返回值的任务就是一个实现了runnable接口的类.使用run方法.
  • 有返回值的任务是一个实现了callable接口的类.使用call方法。Callable与Future同步使用。
import java.util.concurrent.*;
    //有返回结果的任务创建,实现了callable接口的任务类
    public static class  MyCallable  implements Callable{
        private int flag = 0;
        public MyCallable(int flag){
            this.flag = flag;
        }

        public String call() throws Exception{
            if (this.flag == 0){
                return "Thread [" + Thread.currentThread().getName() + "flag = 0";
            }
            if (this.flag == 1){
                try {
                    while (true) {
                        System.out.println("Thread [" + Thread.currentThread().getName() + "] looping.");
                        Thread.sleep(2000);
                    }
                } catch (InterruptedException e) {
                    System.out.println("Thread [" + Thread.currentThread().getName() + "Interrupted");
                }
                return "Thread [" + Thread.currentThread().getName() + "false";
            } else {
                throw new Exception("Thread [" + Thread.currentThread().getName() + " Bad flag value!");
            }
        }
    }

    @Test
    public void testCallable(){
        // 定义3个Callable类型的任务
        MyCallable task1 = new MyCallable(0);
        MyCallable task2 = new MyCallable(1);
        MyCallable task3 = new MyCallable(2);
        // 创建一个执行任务的服务
        ExecutorService es = Executors.newFixedThreadPool(3);
        try {
            // 提交并执行任务,任务启动时返回了一个Future对象,
            // 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作
            Future future1 = es.submit(task1);
            // 获得第一个任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行
            System.out.println("task1: " + future1.get());
            Future future2 = es.submit(task2);
            // 等待5秒后,再停止第二个任务。因为第二个任务进行的是无限循环
            Thread.sleep(5000);
            System.out.println("task2 cancel: " + future2.cancel(true));
            // 获取第三个任务的输出,因为执行第三个任务会引起异常
            // 所以下面的语句将引起异常的抛出
            Future future3 = es.submit(task3);
            System.out.println("task3: " + future3.get());
        } catch (Exception e){
            System.out.println(e.toString());
        }
        // 停止任务执行服务
        es.shutdownNow();
    }

Callable和Runnable的区别如下

  • Callable定义的方法是call,而Runnable定义的方法是run。
  • Callable的call方法可以有返回值,而Runnable的run方法不能有返回值。
  • Callable的call方法可抛出异常,而Runnable的run方法不能抛出异常。

Future表示异步计算的结果,即callable的返回值,它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。Future的cancel方法可以取消任务的执行,它有一布尔参数,参数为 true 表示立即中断任务的执行,参数为 false 表示允许正在运行的任务运行完成。Future的 get 方法等待计算完成,获取计算结果。


Java任务执行:通过java.util.concurrent.ExecutorService接口对象来执行任务,该对象有两个方法可以执行任务execute和submit。execute这种方式提交没有返回值,也就不能判断是否执行成功。submit这种方式它会返回一个Future对象,通过future的get方法来获取返回值,get方法会阻塞住直到任务完成。

    public static class  MyRunnable  implements Runnable{
        static int flag = 0;
        int index;

        public MyRunnable(int index){
            this.index = index;
        }

        @Override
        public void run() {
            flag +=1;
            System.out.println("Thread [" + Thread.currentThread().getName() + "] "+ index+": flag = " + flag);
        }
    }

    @Test
    public void testRunnable(){
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
                .setNameFormat("demo-pool-%d").build();
        ExecutorService pool = new ThreadPoolExecutor(5, 200,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.CallerRunsPolicy());

        for(int i=0;i<5000;i++) {
            //实例化1000个任务,执行call函数
            MyRunnable mr = new MyRunnable(i);
//            pool.execute(mr);     //无返回值的执行任务
            pool.submit(mr);        //有返回值的执行任务
        }

        try {
            //不加这个,程序完不成1000个任务,就提前随主进程退出了
            //每隔1秒,检查一次线程池任务是不是都结束了
            pool.awaitTermination(1, TimeUnit.SECONDS);
            System.out.println(MyRunnable.flag+"------------");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

java关闭线程池: https://www.jianshu.com/p/edd7cb4eafa0

shutdown()     //不再接收新的任务,如果线程池内有任务,那么把这些任务执行完毕后,关闭线程池
shutdownNow()  //不再接受新的任务,并把任务队列中的任务直接移出掉,如果有正在执行的,尝试进行停止;
awaitTermination(1, TimeUnit.SECONDS);  //每隔1秒,检查一次线程池任务是不是都结束了,等待所有任务都结束后运行至后续代码


线程池的使用大体步骤

1、创建任务,实现runnable或callable的类,实例化后提交给线程池,由线程池来安排运行、停止;

2、ThreadPoolExecutor创建线程池,然后通过threadPool.execute(new Job());提交任务到线程池,

3、执行完线程池创建、提交任务到线程池后,就由操作系统来维护线程的调用,即execute的执行逻辑,与创建时的参数相关;

4、线程池中线程的数量:如果是io密集型任务,可以多配置线程;如果是cpu密集型任务,尽量少些线程;

5、线程池关闭:pool.awaitTermination(1, TimeUnit.SECONDS) 会每隔一秒钟检查一次是否执行完毕

6、execute与submit基本一致,区别是submit可以返回Future对象

7、Future,ArrayBlockingQueue,ThreadFactory...

8、  策略  

 

java线程池:

  1. 任务(Job,Task)就是一个 Runnable类型的对象,任务的执行方法就是 Runnable类型对象的run()方法。
  2. 一个任务通过 java.util.concurrent.ThreadPoolExecutor.execute(Runnable)方法被添加到线程池;
  3. 对比线程、线程池,任务其实就是线程,实例化一堆不同参数的含run()方法类,executer的submit追加到线程池,并由系统决定运行;返回一个Future对象
  4. 任务应该就是一个概念,是线程池模式中的线程,由处理的场景、业务可以归纳为任务;
  5. 当系统需要处理非常多的执行时间很短的请求,如果每一个请求都开启一个新线程的话,系统就要不断的进行线程的创建和销毁,有时花在创建和销毁线程上的时间会比线程真正执行的时间还长。而且当线程数量太多时,系统不一定能受得了;

多线程 VS 线程池:

多线程弊端

  • a. 每次new Thread新建对象性能差。
  • b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
  • c. 缺乏更多功能,如定时执行、定期执行、线程中断。

使用线程池目的

  • 线程是稀缺资源,不能频繁的创建。
  • 解耦作用;线程的创建与执行完全分开,方便维护。
  • 应当将其放入一个池子中,可以给其他任务进行复用。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值