java线程,线程池

线程状态

NEW 状态是指线程刚创建, 尚未启动

RUNNABLE 状态是线程正在正常运行中, 当然可能会有某种耗时计算/IO等待的操作/CPU时间片切换等,
这个状态下发生的等待一般是其他系统资源, 而不是锁, Sleep等

BLOCKED 这个状态下, 是在多个线程有同步操作的场景, 比如正在等待另一个线程的synchronized 块的执行释放,
或者可重入的 synchronized块里别人调用wait() 方法, 也就是这里是线程在等待进入临界区
WAITING 这个状态下是指线程拥有了某个锁之后, 调用了他的wait方法, 等待其他线程/锁拥有者调用 notify / notifyAll
一遍该线程可以继续下一步操作, 这里要区分 BLOCKED 和 WATING 的区别, 一个是在临界点外面等待进入,
一个是在理解点里面wait等待别人notify, 线程调用了join方法 join了另外的线程的时候, 也会进入WAITING状态,
等待被他join的线程执行结束

TIMED_WAITING 这个状态就是有限的(时间限制)的WAITING, 一般出现在调用wait(long),
join(long)等情况下, 另外一个线程sleep后, 也会进入TIMED_WAITING状态

TERMINATED 这个状态下表示 该线程的run方法已经执行完毕了, 基本上就等于死亡了(当时如果线程被持久持有, 可能不> 会被回收)

线程创建方式

继承Thread类

public class MyThread extends Thread {

    @Override
    public void run() {
        System.out.println("MyThread");
    }

    public static void main(String[] args) {
        new MyThread().start();
    }
}

实现runnable接口

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println("My Runnable");
    }

    public static void main(String[] args) {
        new Thread(new MyRunnable()).start();
    }

}

注意,这样会调用重写的Thread的run方法,而不是你实现接口的run方法,因为接口的run方法是在Thread的原始run方法中调用的

@Override
public void run() {
if (target != null) {
target.run();
}
}

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println("My Runnable");
    }

    public static void main(String[] args) {
        new Thread(new MyRunnable()){

            @Override
            public void run() {
                System.out.println("重写Thread的run方法");
            }

        }.start();;
    }
}

Callable和FutureTask(runnable无法返回数据,callable可以)

public class MyCallable implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        //让线程停5秒
        Thread.sleep(5000);
        return 1;
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        FutureTask<Integer> futureTask = new FutureTask<>(new MyCallable());
        new Thread(futureTask).start();
        //get方法会等待,等待线程返回
        System.out.println(futureTask.get());
    }

}

线程池

ThreadPoolExecutor
主要有一下这些参数

corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;
maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;
keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
unit:参数keepAliveTime的时间单位,有7种取值
workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响


同时java提供了Executors工具类来方便的创建线程池

newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

public static void main(String[] args) {
        ExecutorService pool = Executors.newSingleThreadExecutor();
        pool.execute(new MyRunnable());
        //pool.shutdown();
    }

newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(5);
        for(int i = 0; i < 10; ++i){
            final int index = i;
            pool.execute(new Runnable() {

                @Override
                public void run() {
                    System.out.println(index);
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

public static void main(String[] args) {
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
        pool.schedule(new Runnable() {

            @Override
            public void run() {
                System.out.println("线程延迟5秒执行");
            }
        }, 5, TimeUnit.SECONDS);
    }
public static void main(String[] args) {
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
        pool.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                System.out.println("从0秒开始,每隔2秒周期性执行");
            }
        }, 0, 2, TimeUnit.SECONDS); 
    }

scheduleAtFixedRate :这个是按照固定的时间来执行,简单来说:到点执行
scheduleWithFixedDelay:这个呢,是等上一个任务结束后,在等固定的时间,然后执行。简单来说:执行完上一个任务后再执行


这里写图片描述

execute和submit方法的区别

  1. execute只能接受runnable,submit**还**可以接受callable
  2. execute没有返回值,submit有返回值
  3. execute异常会直接抛出,submit要get结果才能收到异常

参考
https://blog.csdn.net/cpf2016/article/details/50150205
https://www.cnblogs.com/goody9807/p/6515128.html
https://www.cnblogs.com/ElEGenT/p/6392465.html
https://www.cnblogs.com/baby-bear/p/4058534.html

猜你喜欢

转载自blog.csdn.net/a1065712890/article/details/80958474