五、线程池

线程池

提前创建好若干个线程放在一个容器中。如果有任务需要处理,则将任务 直接分配给线程池中的线程来执行,任务处理完以后这个线程不会被销毁, 而是等待后续分配任务

一下4个线程,其实都是ThreadPoolExecutor的实现类。

  • newFixedThreadPool

    • 创建一个固定数量的线程池
  • newSingleThreadExecutor

    • 创建只有一个线程的线程池
  • newCachedThreadPool

    • 创建一个可以根据实际情况调整的线程池
  • newScheduledThreadPool

    • 创一个带调度定时任务的线程池(延迟执行、周期性执行的线程池:类似于定时器的功能)
public class ThreadPoolDemo implements Runnable{

    public static void main(String[] args) {

        ExecutorService executorService=Executors.newFixedThreadPool(3);
        executorService.prestartAllCoreThreads(); //可以提前预热所有核心线程
        for (int i = 0; i < 100; i++) {
            executorService.execute(new ThreadPoolDemo());
        }
        executorService.shutdown();
    }
    @Override
    public void run() {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName());
    }
}

线程池的6大参数

核心线程数,相当于正式工

最大线程数,相当于外包可增加可减少

keepAliveTime:超时时间, 超出核心线程以外的线程的生存周期。

unit:存活的时间单位

workQueue:保存等待执行任务的队列

threadFactory:创建新线程使用的工厂

在这里插入图片描述

线程池原理图:

在这里插入图片描述

一、线程池的监控

继承线程池,之前说的4中线程的实现方法本身就是ThreadPoolExcutor的4中实现

public class ThreadPoolSelf extends ThreadPoolExecutor {

    public ThreadPoolSelf(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    @Override
    public void shutdown() {
        super.shutdown();
    }

    //任务执行开始
    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        //TODO 通过一个属性来记录任务的开始时间
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        //任务执行结束
        System.out.println("初始线程数:"+this.getPoolSize());
        System.out.println("核心线程数:"+this.getCorePoolSize());
        System.out.println("正在执行的任务数量:"+this.getActiveCount());
        System.out.println("已经执行的任务数:"+this.getCompletedTaskCount());
        System.out.println("任务总数"+this.getTaskCount());
    }
}

二、带返回值的线程及原理

带返回值的线程使用submit方法

public class CallableFutureDemo implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println("Hello Mic");
        Thread.sleep(3000); //睡眠3s
        return "Mic";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
       /* CallableFutureDemo callableFutureDemo=new CallableFutureDemo();
        FutureTask futureTask=new FutureTask(callableFutureDemo);
        new Thread(futureTask).start();
        //get方法是属于阻塞方法
        System.out.println(futureTask.get());*/

        ExecutorService executorService = Executors.newFixedThreadPool(1);
        CallableFutureDemo callableFutureDemo = new CallableFutureDemo();
        Future future = executorService.submit(callableFutureDemo);
        System.out.println(future.get());

    }
}

三、一不小心死锁了怎么办

3.1 死锁的4个条件,需要同时满足

  1. 互斥,共享资源 X 和 Y 只能被一个线程占用;

  2. 占有且等待,线程 T1 已经取得共享资源 X,在等待共享资源 Y 的时候, 不释放共享资源 X;

  3. 不可抢占,其他线程不能强行抢占线程 T1 占有的资源;

  4. 循环等待,线程 T1 等待线程 T2 占有的资源,线程 T2 等待线程 T1 占 有的资源,就是循环等待。

解决方案:

  1. 一次性申请所有资源,这样就不存在等待了
  2. 占用一部分资源的线程可以继续申请资源,申请不到需要主动释放其他占有的资源
  3. 按照申请的顺序进行资源的预占用,规避循环等待

转账案例:

会出现死锁

public class Account {
    private String accountName;
    private int balance; //余额

    public Account(String accountName, int balance) {
        this.accountName = accountName;
        this.balance = balance;
    }
    public void debit(int amount){
        this.balance-=amount;
    }
    public void credbit(int amount){
        this.balance+=amount;
    }
}
public class TransferAccount implements Runnable{
    private Account fromAccount; //转出账户
    private Account toAccount; //转入账户
    private int amount;// 转出金额

    public TransferAccount(Account fromAccount, Account toAccount, int amount) {
        this.fromAccount = fromAccount;
        this.toAccount = toAccount;
        this.amount = amount;
    }

    @Override
    public void run() {
        while(true){
            synchronized (fromAccount){
                synchronized (toAccount){
                    if(fromAccount.getBalance()>=amount){
                        fromAccount.debit(amount);
                        toAccount.credbit(amount);
                    }
                }
                System.out.println(fromAccount.getAccountName()+"----"+fromAccount.getBalance());
                System.out.println(toAccount.getAccountName()+"----"+toAccount.getBalance());
            }
        }
    }
}

3.2 方案一

一次性申请所有资源 新建一个锁对象。

public class Allocator {

    private List<Object> list = new ArrayList<>();
    /**
     * 申请资源
     * @param from
     * @param to
     * @return
     */
    synchronized boolean apply(Object from,Object to){
        // list不为空,说明别的线程有占用
        if(list.contains(from) || list.contains(to)){
            return false;
        }else {
            // 可申请,并把锁加入
            list.add(from);
            list.add(to);
            return true;
        }
    }
    synchronized void free(Object from,Object to){
        list.remove(from);
        list.remove(to);
    }
}
public class TransferAccount01 implements Runnable{
    private Account fromAccount; //转出账户
    private Account toAccount; //转入账户
    private int amount;// 转出金额
    Allocator allocator;// 新的锁对象

    public TransferAccount01(Account fromAccount, Account toAccount, int amount,Allocator allocator) {
        this.fromAccount = fromAccount;
        this.toAccount = toAccount;
        this.amount = amount;
        this.allocator=allocator;
    }

    @Override
    public void run() {
        while(true){
            if(allocator.apply(fromAccount,toAccount)) { //都会在这个地方去获得临界资源
                try {
                    synchronized (fromAccount) {
                        synchronized (toAccount) {//申请不到资源,就已经阻塞
                            if (fromAccount.getBalance() >= amount) {
                                fromAccount.debit(amount);
                                toAccount.credbit(amount);
                            }
                        }
                        System.out.println(fromAccount.getAccountName() + "----" + fromAccount.getBalance());
                        System.out.println(toAccount.getAccountName() + "----" + toAccount.getBalance());
                    }
                }finally {
                    allocator.free(fromAccount,toAccount);
                }
            }
        }
    }
}

3.3 方案二

占用一部分资源的线程可以继续申请资源,申请不到需要主动释放其他占有的资源

public class TransferAccount02 implements Runnable {
    private Account fromAccount; //转出账户
    private Account toAccount; //转入账户
    private int amount;// 准出金额
    Lock fromLock = new ReentrantLock();
    Lock toLock = new ReentrantLock();

    public TransferAccount02(Account fromAccount, Account toAccount, int amount) {
        this.fromAccount = fromAccount;
        this.toAccount = toAccount;
        this.amount = amount;
    }

    @Override
    public void run() {
        while (true) {
            if (fromLock.tryLock()) {
                if (toLock.tryLock()) {
                    if (fromAccount.getBalance() >= amount) {
                        fromAccount.debit(amount);
                        toAccount.credbit(amount);
                    }
                    System.out.println(fromAccount.getAccountName() + "----" + fromAccount.getBalance());
                    System.out.println(toAccount.getAccountName() + "----" + toAccount.getBalance());
                }
            }
        }
    }
}

3.4 方案三

按照申请的顺序进行资源的预占用,规避循环等待

三、ConcurrentHashMap

J.U.C包中提供的线程安全比那个且高效的HashMap

ount.getAccountName() + “----” + fromAccount.getBalance());
System.out.println(toAccount.getAccountName() + “----” + toAccount.getBalance());
}
}
}
}
}




### 3.4 方案三

按照申请的顺序进行资源的预占用,规避循环等待



## 三、ConcurrentHashMap

> J.U.C包中提供的线程安全比那个且高效的HashMap 

![在这里插入图片描述](https://img-blog.csdnimg.cn/8a860a1b63b54892a68432f21a8a2026.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAdTAxMDg2ODE5Mg==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值