多线程大杂烩

本文详细介绍了多线程中的死锁问题,包括其定义、产生条件及解决策略。深入讲解了线程的wait、notify、notifyAll方法以及它们的使用规范。接着探讨了LockSupport的park和unpark方法,对比了它们与sleep、wait的区别。最后,文章详细阐述了线程池的概念、创建方式、执行流程、拒绝策略以及线程池关闭,并讨论了ThreadLocal的使用场景和可能导致的内存溢出问题。
摘要由CSDN通过智能技术生成

死锁:
(1)定义:在多线程中(两个或以上线程),因为资源抢占而造成线程无限等待的问题。由于一个线程可以拥有多把锁,但是一个锁只能被一个线程拥有。
(2)死锁造成的四个因素(同时):
1.互斥条件(一个资源只能被一个线程持有);
2.请求拥有条件(一个线程持有了一个资源之后,又请求另一个资源);
3.不可剥夺条件(一个资源被一个线程拥有之后,如果这个线程不释放此资源,那么其他线程不能强制获得此资源);
4.环路等待条件(多个线程在获取资源时形成了一个环形链);
(3)如何解决死锁的问题?
从以下两个条件入手,修改以下条件任意一个:
1.请求拥有条件
2.环路等待条件:
解决死锁可以通过控制获取锁的顺序来解决死锁问题(破坏环路等待条件)。
线程等待:
sleep休眠缺陷:必须传递一个明确的结束时间。
线程的通讯机制:一个线程的动作可以让另一个线程感知到。
wait(线程休眠)/notify(线程唤醒)/nofifyAll(唤醒当前锁对应的全部线程)
1.在使用以上方法时必须要加锁;
wait为什么要加锁?
因为在进行wait操作时,会先释放锁;
为什么要释放锁?
因为wait在不传任何参数时,默认是永久等待,这样会造成一个资源一直被占用。
2.加锁对象和以上方法的加锁对象必须保持一致;
3.一组wait(休眠)/notify(唤醒)/nofifyAll(唤醒全部)必须加同一把锁;
4.notifyAll只能唤醒当前对象对应的线程;
sleep(0)和wait(0)的区别:
1.sleep是Thread的一个静态方法;而wait是Object的方法;
2.sleep(0)立即触发一次CPU资源的抢占,wait(0)代表永久的等待下去;
wait和sleep区别:
相同点:
都可以让当前线程休眠;
都必须要处理一个Interrupt的异常;
不同点:
wait来自于Object中的一个方法,而sleep来自Thread类;
传参不同,wait可以没有参数,而sleep必须有一个大于0的参数;
wait必须要加锁,sleep使用时不用加锁;
wait使用时会释放锁,sleep没有锁;
wait默认不传参的情况下,会进入WAITING状态,sleep会进入TIMEDWAITING状态;
为什么wait会放到Object中而不是Thread?
wait必须要加锁和释放锁,而锁属于对象级别,而非线程级别(一个线程线程拥有多把锁),为了灵活起见(释放哪把锁),就把wait放在Object中。
LockSupport.park()方法——新版本休眠——WAITING——不用加锁,不用处理异常
LockSupport.unpark(线程)方法——新版本唤醒休眠——可以控制线程唤醒顺序,不能和notify等混用
LockSupport.parkUntil(休眠时间)与wait区别:
相同点:
1.都可以线程休眠;
2.都可以传参不传参,并且线程状态一致;
不同点:
1.wait必须要配合synchronized一起使用(加锁),而LockSupport不用;
2.wait只能唤醒全部和随机的一个线程,而LockSupport可以唤醒指定线程;
线程池:
1.线程的创建需要开辟内存资源:本地方法栈、Java虚拟机栈、程序计数器等线程私有变量的内存,频繁的创建和销毁会造成性能问题;
2.使用线程不能很好的管理任务和友好的拒绝任务;
定义:使用池化技术来管理和使用线程的技术就叫做线程池。
线程池的创建方式总共包含七种:
方式一:创建固定个数的线程池;Executors——当对当前代码执行很了解,知道执行多少个任务

 public static void main(String[] args) {
   
        //创建固定个数的线程池
      ExecutorService executorService=Executors.newFixedThreadPool(5);
      //执行一个任务
       /* executorService.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程名"+Thread.currentThread().getName());
            }
        });*/
       //执行多个任务
        for (int i = 0; i < 10; i++) {
   
            executorService.execute(new Runnable() {
   
                @Override
                public void run() {
   
                    System.out.println("线程名"+Thread.currentThread().getName());
                }
            });
        }

    }

创建了10个线程的线程池来执行两个任务,实际创建了几个线程?答案:2个
线程池执行流程:当拿到一个任务之后,会判断当前线程池里面的线程数量是否达到最大值,如果没有就创建新的线程执行任务;当任务来了之后,线程池的线程数量已经是最大值,并且没有空闲线程,那么会将任务放到任务队列中等待执行;
线程池里面的两个重要任务:
1.线程;
2.任务队列;

方式二:创建带缓存的线程池;——当有大量短期任务的时候适用,根据任务的数量来创建对应的线程数;

 public static void main(String[
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值