多线程基础二

目录

一、线程的状态:

1、NEW:新建状态,新创建的线程,此时尚未调用start()方法;

2、Runnable:运行状态,运行中的线程,已经调用start()方法,线程正在或即将执行run()方法;

3、Blocked:阻塞状态:运行中的线程,在等待竞争锁时,被阻塞,暂不执行;

4、Waiting:等待状态,运行中的线程,因为join()wait()等方法调用,进入等待。 notify() notifyAll()方法唤醒线程 -- 锁对象让等待的对象唤醒

5、TimedWaiting:计时等待状态,计时等待状态,运行中的线程,因为执行sleep(等待毫秒值)join(等待毫秒值)等方法,进入计时等待;

6、Terminated:终止状态,终止状态,线程已终止,因为run()方法执行完毕。

二、lock锁:

1、Lock接口的主要实现类:

(1)ReentrantLock:可重入锁,最常用的实现类

(2)ReentrantReadWriteLock.ReadLock:读锁

(3)ReentrantReadWriteLock.WriteLock:写锁

2、核心方法:

(1)lock():获取锁,如果锁被其他线程持有,则当前线程会阻塞

(2)lockInterruptibly():获取锁,但可以被中断

(3)tryLock():尝试获取锁,立即返回,获取成功返回true,否则返回false

(4)tryLock(long time, TimeUnit unit):在指定时间内尝试获取锁

(5)unlock():释放锁

(6)newCondition():创建一个与该锁相关联的Condition对象

三、线程池:

1、线程池的常用类和接口:

(1)ExecutorService接口:进行线程池的操作访问;

(2)Executors类:创建线程池的工具类;

(3)ThreadPoolExecutor及其子类:封装线程池的核心参数和运行机制;

2、关闭线程池:

(1)shutdown()方法关闭线程池的时候,它会等待正在执行的任务先完成,然后再关闭。

(2)shutdownNow()会立刻停止正在执行的任务;

(3)awaitTermination()方法时,主线程会处于一种等待的状态,按照指定的timeout检查线程池。第一个参数指定的是时间,第二个参数指定的是时间单位(当前是秒)。返回值类型为boolean型。该方法经常与shutdown()方法配合使用,用于检测线程池中的任务是否已经执行完毕:

3、使用Executors工具类创建线程池对象:

(1)newFixedThreadPool(int   nThreads ):通过工具类获取线程池对象 有上限

(2)newCachedThreadPool():线程数根据任务动态调整的线程池,创建一个线程数量无上限的线程池对象

(3)newSingleThreadExecutor():仅提供一个单线程的线程池

(4)newScheduledThreadPool():能实现定时,周期性任务的线程池

4、使用ThreadPoolExecutor类创建线程池对象:

(1)、创建线程池对象:ExecutorService es = new ThreadPoolExecutor( .......);

(1.1)  int corePoolSize, 核心线程数

(1.2)int maximumPoolSize, 最大线程数(核心+非核心(临时))

(1.3) long keepAliveTime, 临时线程最大存活时间

(1.4) TimeUnit unit, 存活的时间单位

(1.5)BlockingQueue workQueue, 等待队列

(1.6)ThreadFactory threadFactory, 线程工厂 创建线程

(1.7)RejectedExecutionHandler handler 拒绝策略

5、线程池的优点:

(1)提高响应的速度

(2)提高线程的可管理性

(3)降低资源消耗(线程执行充任务,不销毁,可以执行其他的年务)

四、线程池分类总结:

1、FixedThreadPool:

(1)线程池参数:

(1.1)核心线程数和最大线程数一致

(1.2)非核心线程线程空闲存活时间,即keepAliveTime为0

(1.3)阻塞队列为无界队列LinkedBlockingQueue

(2)工作机制:

(2.1)提交线程任务

(2.2)如果线程数少于核心线程,创建核心线程执行任务

(2.3)如果线程数等于核心线程,把任务添加到LinkedBlockingQueue阻塞队列

(2.4)如果线程执行完任务,去阻塞队列取任务,继续执行

(3)使用场景: 适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。

2、CachedThreadPool:

(1)线程池参数:

(1.1)核心线程数为0

(1.2)最大线程数为Integer.MAX_VALUE​​​​​

(1.3)工作队列是SynchronousQueue同步队列

(1.4)非核心线程空闲存活时间为60秒

(2)工作机制:

(2.1)提交线程任务

(2.2)因为核心线程数为0,所以任务直接加到SynchronousQueue工作队列

(2.3)判断是否有空闲线程,如果有,就去取出任务执行

(2.4)如果没有空闲线程,就新建一个线程执行

(2.5)执行完任务的线程,还可以存活60秒,如果在这期间,接到任务,可以继续存活下去;否则,被销毁。

(3)使用场景: 用于并发执行大量短期的小任务。

3、SingleThreadExecutor:单线程化的线程池

(1)线程池参数:

(1.1)核心线程数为1

(1.2)最大线程数也为1

(1.3)阻塞队列是LinkedBlockingQueue

(1.4)非核心线程空闲存活时间为0秒

(2)使用场景: 适用于串行执行任务的场景,将任务按顺序执行。

4、ScheduledThreadPool:能实现定时、周期性任务的线程池

(1)线程池参数:

(1.1)最大线程数为Integer.MAX_VALUE 

(1.2)阻塞队列是DelayedWorkQueue

(1.3)keepAliveTime为0

(2)使用场景: 周期性执行任务,并且需要限制线程数量的需求场景。

四、线程池注意事项:


一、线程的状态:

         在Java程序中,一个线程对象通过调用start()方法启动线程,并且在线程获取CPU时,自动执行run()方法。run()方法执行完毕,代表线程的生命周期结束。整个线程的生命周期中,线程的状态有以下6种:

1、NEW:新建状态,新创建的线程,此时尚未调用start()方法;

public class Demo01 {
    //NEW:新建状态,新创建的线程,此时尚未调用start()方法
    public static void main(String[] args) {
        Thread t1 = new Thread(){
            @Override
            public void run() {
                System.out.println("正在执行某个任务");
            }
        };
        System.out.println(t1.getState());
    }
}

2、Runnable:运行状态,运行中的线程,已经调用start()方法,线程正在或即将执行run()方法;

public class Demo02 {
    //RUNNABLE运行状态,运行中的线程,已经调用户start()方法,线程正在或即将执行run方法
    public static void main(String[] args) {
        Thread t1 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i <100 ; i++) {
                    System.out.println("正在执行某个任务");
                }
            }
        };
        System.out.println(t1.getState());
    }
}

3、Blocked:阻塞状态:运行中的线程,在等待竞争锁时,被阻塞,暂不执行;

package com.yuan.state;

public class Demo04 {
    public static void main(String[] args) throws InterruptedException {
        Object obj=new Object();
        Runnable r1 = new Runnable(){
            @Override
            public void run() {
                synchronized (obj){
                    while (true){
                        //死循环,只能执行一个,另一个等待
                    }
                }
            }
        };
        Thread t1 = new Thread(r1, "线程1:");
        Thread t2 = new Thread(r1, "线程2:");

        t1.start();
        t2.start();
        //让主线程休眠,让t1和t2同时竞争一个锁资源  有一个会阻塞
        Thread.sleep(100);
        System.out.println(t1.getName()+t1.getState());
        System.out.println(t2.getName()+t2.getState());
    }
}

4、Waiting:等待状态,运行中的线程,因为join()wait()等方法调用,进入等待。 notify() notifyAll()方法唤醒线程 -- 锁对象让等待的对象唤醒

package com.yuan.state;

public class Demo06 {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        Runnable r1 = new Runnable() {

            @Override
            public void run() {
                synchronized (obj) {
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        Thread t1 = new Thread(r1, "线程1:");
        t1.start();

        Thread.sleep(100);
        System.out.println(t1.getName() + t1.getState());

    }
}

5、TimedWaiting:计时等待状态,计时等待状态,运行中的线程,因为执行sleep(等待毫秒值)join(等待毫秒值)等方法,进入计时等待;

package com.yuan.state;

public class Demo05 {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        Runnable r1 = new Runnable(){
            @Override
            public void run() {
                synchronized (obj){
                    try {
                        //Thread.sleep(1000*5) //不释放
                        obj.wait(1000*5); //释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        Thread t1 = new Thread(r1, "线程1:");
        Thread t2 = new Thread(r1, "线程2:");

        t1.start();
        t2.start();
        //让主线程休眠,让t1和t2同时竞争一个锁资源
        Thread.sleep(100);
        System.out.println(t1.getName()+t1.getState());
        System.out.println(t2.getName()+t2.getState());
    }
}

6、Terminated:终止状态,终止状态,线程已终止,因为run()方法执行完毕。

public class Demo03 {
    public static void main(String[] args) throws InterruptedException {
       //Terminated:终止状态,线程已终止,因为run()方法执行完毕
        Thread t1 = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i <100 ; i++) {
                    System.out.println("正在执行某个任务");
                }
            }
        };
        t1.start();
        //等待t1执行完毕,执行mian线程
        Thread.sleep(1000);
        System.out.println(t1.getState());
    }
}

二、lock锁:

        在 Java 中,Lock是 Java 5 引入的一个接口,位于java.util.concurrent.locks包下,它提供了比synchronized关键字更灵活、更强大的线程同步机制。

1、Lock接口的主要实现类:

(1)ReentrantLock:可重入锁,最常用的实现类
(2)ReentrantReadWriteLock.ReadLock:读锁
(3)ReentrantReadWriteLock.WriteLock:写锁

2、核心方法:

(1)lock():获取锁,如果锁被其他线程持有,则当前线程会阻塞
(2)lockInterruptibly():获取锁,但可以被中断
(3)tryLock():尝试获取锁,立即返回,获取成功返回true,否则返回false
(4)tryLock(long time, TimeUnit unit):在指定时间内尝试获取锁
(5)unlock():释放锁
(6)newCondition():创建一个与该锁相关联的Condition对象
package com.yuan.lock;

import java.util.Hashtable;

public class DeadLock {
    private static  Object obj1=new Object();
    private static Object obj2=new Object();

    public void add() throws InterruptedException {
        synchronized (obj1){
            System.out.println("进入到add方法中");
            Thread.sleep(1000);
            synchronized (obj2){
                System.out.println("add方法执行结束");
            }
        }
    }
    public void desc() throws InterruptedException {
        synchronized (obj2){
            System.out.println("进入到desc方法中");
            Thread.sleep(1000);
            synchronized (obj1){
                System.out.println("desc方法执行结束");
            }
        }
    }
}
class Demo02 {
    public static void main(String[] args) throws InterruptedException {
        DeadLock dl = new DeadLock();

        Thread t1 = new Thread(){
            @Override
            public void run() {
                try {
                    dl.add();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run() {
                try {
                    dl.desc();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        Thread.sleep(1000*2);
        t2.start();
    }
}

三、线程池:

        线程池内部维护了若干个线程,没有任务的时候,这些线程都处于等待空闲状态。如果有新的线程任务,就分配一个空闲线程执行。如果所有线程都处于忙碌状态,线程池会创建一个新线程进行处理或者放入队列(工作队列)中等待。

1、线程池的常用类和接口:

(1)ExecutorService接口:进行线程池的操作访问;
(2)Executors类:创建线程池的工具类;
(3)ThreadPoolExecutor及其子类:封装线程池的核心参数和运行机制;

2、关闭线程池:

(1)shutdown()方法关闭线程池的时候,它会等待正在执行的任务先完成,然后再关闭。
(2)shutdownNow()会立刻停止正在执行的任务;
(3)awaitTermination()方法时,主线程会处于一种等待的状态,按照指定的timeout检查线程池。第一个参数指定的是时间,第二个参数指定的是时间单位(当前是秒)。返回值类型为boolean型。该方法经常与shutdown()方法配合使用,用于检测线程池中的任务是否已经执行完毕:

3、使用Executors工具类创建线程池对象:

package com.yuan.executor;

public class MyRun implements Runnable {
    String str;

    public MyRun(String str) {
        this.str = str;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "正在执行" + str);
        try {
            Thread.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "结束执行任务" + str);

    }
}
(1)newFixedThreadPool(int   nThreads ):通过工具类获取线程池对象 有上限
public class Demo01 {
    public static void main(String[] args) throws InterruptedException {
        //通过工具类获取线程池对象   有上限
        ExecutorService es= Executors.newFixedThreadPool(3);
        //2、提交任务给线程池对象
        es.execute(new MyRun("任务1"));
        es.execute(new MyRun("任务2"));
        es.execute(new MyRun("任务3"));
        Thread.sleep(1000);
        es.execute(new MyRun("任务4"));
        //3、线程池的关闭方法
        es.shutdown(); //1、会等待正在执行的任务先完成,然后再关闭
//        es.shutdownNow(); //2、会立刻停止正在执行的任务

        //每隔1毫秒检查一次线程池的任务执行状态
        while(!es.awaitTermination(1, TimeUnit.SECONDS)){
            System.out.println("还没有关闭线程池");
        }
        System.out.println("已经关闭线程池");

    }
}
(2)newCachedThreadPool():线程数根据任务动态调整的线程池,创建一个线程数量无上限的线程池对象
public class Demo02 {
    public static void main(String[] args) throws InterruptedException {
        //创建一个线程数量无上限的线程池对象
        ExecutorService es = Executors.newCachedThreadPool();
        //循环的提交任务
        for (int i = 0; i <=9 ; i++) {
            es.execute(new MyRun("任务"+i));
        }
        Thread.sleep(1000*7);
        es.execute(new MyRun("最后的一个任务"));

        es.shutdown();

    }
}
(3)newSingleThreadExecutor():仅提供一个单线程的线程池
public class Demo03 {
    public static void main(String[] args) {
        //newSingleThreadExecutor():仅提供一个单线程的线程池
        ExecutorService es = Executors.newSingleThreadExecutor();

        for (int i = 0; i <=9; i++) {
            es.execute(new MyRun("任务"+i));
        }
        es.shutdown();
    }
}
(4)newScheduledThreadPool():能实现定时,周期性任务的线程池
public class Demo04 {
    public static void main(String[] args) {
        //能实现定时,周期性任务的线程池
        ScheduledExecutorService es = Executors.newScheduledThreadPool(2);

        Runnable r1 = new Runnable(){

            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"正在执行");
            }
        };
        //2.提交任务--延时多久进行任务的执行

        // command-任务对象,delay-延时的时间,unit-时间单位
        // es.schedule(r1,2,Timeunit.SECONDS);

        // scheduleAtFixedRate延时2秒首次执行此任务,每隔5秒进行此任务的执行
         es.scheduleAtFixedRate(r1,0,5,TimeUnit.SECONDS);

        // scheduleWithFixedDelay,上一次任务执行完毕后,等待固定的时间间隔,再执行下一次任务;
//        es.scheduleWithFixedDelay(r1,0,3, TimeUnit.SECONDS);

        // 线程池进行资源关闭
//        es.shutdown();
    }
}

4、使用ThreadPoolExecutor类创建线程池对象:

(1)、创建线程池对象:ExecutorService es = new ThreadPoolExecutor( .......);

参数类型: 

(1.1)  int corePoolSize, 核心线程数
(1.2)int maximumPoolSize, 最大线程数(核心+非核心(临时))
(1.3) long keepAliveTime, 临时线程最大存活时间
(1.4) TimeUnit unit, 存活的时间单位
(1.5)BlockingQueue<Runnable> workQueue, 等待队列
(1.6)ThreadFactory threadFactory, 线程工厂 创建线程
(1.7)RejectedExecutionHandler handler 拒绝策略

           ------ThreadPoolExecutor.AbortPolicy()默认拒绝策略 抛出异常 *

           ------ThreadPoolExecutor.DiscardOldestPolicy() 扔掉队列等待时间最长的任务 

           ------ThreadPoolExecutor.DiscardPolicy() 丢弃最后一个 

           ------ThreadPoolExecutor.CallerRunsPolicy() 让现在正在执行的线程执行 main 

public class Demo01 {
    public static void main(String[] args) {

        ExecutorService es = new ThreadPoolExecutor(
                3,
                5,
                60,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
        es.submit(new MyRun("任务1")); //提及送一个任务给es对象
        es.submit(new MyRun("任务2"));
        es.submit(new MyRun("任务3"));
        es.submit(new MyRun("任务4"));//核心线程已满,进入等待队列
        es.submit(new MyRun("任务5"));
        es.submit(new MyRun("任务6"));
        es.submit(new MyRun("任务7"));//等待队列已满,使用临时线程
        es.submit(new MyRun("任务8"));
        es.submit(new MyRun("任务9"));//核心,等待,临时都已满,默认拒绝策略,抛出异常报错
        es.submit(new MyRun("任务10"));

    }
}
class MyRun implements Runnable {
    String str;

    public MyRun(String str) {
        this.str = str;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "正在执行" + str);
//        while (true){
//            //死循环
//        }
        try {
            Thread.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "结束执行任务" + str);

    }
}

5、线程池的优点:

(1)提高响应的速度
(2)提高线程的可管理性
(3)降低资源消耗(线程执行充任务,不销毁,可以执行其他的年务)

四、线程池分类总结:

1、FixedThreadPool:

(1)线程池参数:
(1.1)核心线程数和最大线程数一致
(1.2)非核心线程线程空闲存活时间,即keepAliveTime0
(1.3)阻塞队列为无界队列LinkedBlockingQueue
(2)工作机制
(2.1)提交线程任务
(2.2)如果线程数少于核心线程,创建核心线程执行任务
(2.3)如果线程数等于核心线程,把任务添加到LinkedBlockingQueue阻塞队列
(2.4)如果线程执行完任务,去阻塞队列取任务,继续执行
(3)使用场景: 适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。

2、CachedThreadPool:

(1)线程池参数:
(1.1)核心线程数为0
(1.2)最大线程数为Integer.MAX_VALUE​​​​​
(1.3)工作队列是SynchronousQueue同步队列
(1.4)非核心线程空闲存活时间为60
(2)工作机制
(2.1)提交线程任务
(2.2)因为核心线程数为0,所以任务直接加到SynchronousQueue工作队列
(2.3)判断是否有空闲线程,如果有,就去取出任务执行
(2.4)如果没有空闲线程,就新建一个线程执行
(2.5)执行完任务的线程,还可以存活60秒,如果在这期间,接到任务,可以继续存活下去;否则,被销毁。
(3)使用场景: 用于并发执行大量短期的小任务。

3、SingleThreadExecutor:单线程化的线程池

(1)线程池参数:
(1.1)核心线程数为1
(1.2)最大线程数也为1
(1.3)阻塞队列是LinkedBlockingQueue
(1.4)非核心线程空闲存活时间为0
(2)使用场景: 适用于串行执行任务的场景,将任务按顺序执行。

4、ScheduledThreadPool:能实现定时、周期性任务的线程池

(1)线程池参数:
(1.1)最大线程数为Integer.MAX_VALUE 
(1.2)阻塞队列是DelayedWorkQueue
(1.3)keepAliveTime0
(2)使用场景: 周期性执行任务,并且需要限制线程数量的需求场景。

四、线程池注意事项:

         在《阿里巴巴java开发手册》中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量;另一方面线程的细节管理交给线程池处理,优化了资源的开销。而线程池不允许使用Executors去创建,而要通过ThreadPoolExecutor方式。jdkExecutor框架虽然提供了如newFixedThreadPool()newSingleThreadExecutor()newCachedThreadPool()等创建线程池的方法,但都有其局限性,不够灵活;另外由于前面几种方法内部也是通过new ThreadPoolExecutor方式实现,使用ThreadPoolExecutor有助于大家明确线程池的运行规则,创建符合自己的业务场景需要的线程池,避免资源耗尽的风险。

        必须为线程池中的线程,按照业务规则,进行命名。可以在创建线程池时,使用自定义线程工厂规范线程命名方式,避免线程使用默认名称

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呼哧呼哧.

栓Q!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值