学习心得---异常与线程

本周学习了异常与线程。
首先,我们来讲一下异常,

  1. 异常是指程序在运行过程中出现的特殊情况。任何程序都可能存在大量的未知问题、错误;如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。
  2. 异常有个所有异常或错误的父类Throwable;下面介绍其两个重要的子类:(1)Error:JVM、硬件、执行逻辑错误,不能手动处理。(致命的);(2)Exception:程序在运行和配置过程中产生的问题,可处理。在Exception中又包含两个子类:1)运行时异常(Runtime Exception):可处理,可不处理;2)受查异查(CheckedException):必须处理。
  3. 当程序产生异常时,我们可以选择自动抛出异常或者使用throw new 异常类型来手动抛出异常,产生异常会导致程序因异常儿中止,相当于执行了return语句。
  4. 异常可以进行传递,在方法参数列表后面使用throws声明异常交给调用她的上一级进行处理,如果上一级也不处理,需要继续声明异常继续交给上一级处理,如果最终都没有处理,会由JVM进行默认处理(打印堆栈跟踪信息),而运行时异常可声明也可不声明
  5. 异常的处理使用try{}catch(){}finally{}结构来处理,将可能出现异常的代码放在try中,在catch中捕捉异常并进行处理,而无论是否出现异常都会执行fianlly代码块;使用多重catch时,遵循从子到父的顺序,父类异常在最后(Exception)。
  6. 我们亦可以自定义异常,通过继承Exception或者RuntimeException来实现,其要求子类中要提供无参构造方法以及String message参数的构造方法(使用getMessage()方法读取具体异常)。
  7. 异常方法覆盖的几个原则:(1)父类(接口)中方法声明了异常,子类重写后可声明也可不声明。(2)父类(接口)中方法没有声明异常,则子类也不可声明异常。(3)父类(接口)中方法声明了异常,子类可以声明的异常与其相等或是其子类。(4)子类可以声明比父类更多的异常,必须小于其父类(接口)声明的异常。

接下来,我们来聊一下线程的问题;
1. 首先问一下什么是进程?就是运行时的程序,我们称之为进程。单核CPU在任意时间点上,只能运行一个进程。其原理是宏观并行、微观串行。
2. 线程由称为轻量级线程;是程序中的一个顺序控制流程,也是CPU的基本调度单位;进程可以由单个或多个线程组成,彼此间完成不同的工作,交替执行,称为多线程;JVM虚拟机是一个进程,默认包含主线程(Main函数),可以通过代码创建多个独立线程,与Main线程并发执行。
3. 线程的组成:(1)CPU时间片:操作系统(OS)会为每个线程分配执行时间。(2)运行数据:1)堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象。2)栈空间:存储线程需使用的局部变量,。每个线程都拥有独立的栈。(堆共享,栈独立)(3)线程的逻辑代码。
4. 创建线程的两种方式:
(1)继承Thread类
在这里插入图片描述
(2)实现Runnable接口在这里插入图片描述
5. 常见的方法:
(1)休眠(sleep):
1)public static void sleep(long millis)
2)当前线程主动休眠millis毫秒。
3)直接使用Thread调用:Thread.sleep(1000);
4)使用sleep会抛出异常,使用throws InterruptedException声明或者使用try{} catch(){}解决异常。
(2)放弃(yield)
1)public static void yield()
2)当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片。
3)直接使用Thread调用:Thread.yield();
(3)结合(join)
1)public final void join()
2)允许其他线程加入到当前线程中
3)如果在main中使用该方法:t1.join(),代表main等t1执行结束之后在竞争时间片。
4)使用join会抛出异常,使用throws InterruptedException声明或者使用try{} catch(){}解决异常。
6. 线程安全的问题:
(1)当多线程并发访问临界资源时,如果破坏原子操作,可能会造成数据不一致。
(2)临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可保证其正确性。
(3)原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可打乱或缺省。
7. 两种同步方式:
(1)同步代码块 :synchronized(临界资源对象){//对临界资源对象加锁 //代码(原子操作)}在这里插入图片描述
(2)同步方法
1)只有在调用包含同步代码块的方法,或者同步方法时,才需要对象的锁标记。
2)如调用不包含同步代码块的方法,或者普通方法时,则不需要锁标记,可直接调用。
8. 线程通信
(1)等待:
1)public final void wait()
2)Public final void wait(long timeout)
3)必须在对obj(对象)加锁的同步代码块(或同步方法)中,在一个线程执行期间,调用了obj.wait(),该线程会释放所拥有的锁标记。同时,进入到obj的等待队列中。等待被唤醒。
(2)通知(唤醒)
1)public final void notify()
2)public final void notifyAll()
3)必须在对obj加锁的同步代码块(或同步方法)中,从obj的Waiting(等待队列)中随机释放一个或全部线程。对自身线程无影响。
9. 线程池
1)线程容器,可设定线程分配的数量上限。
2)将预先创建的线程对象存入池中,并重用线程池中的线程对象。
3)避免频繁的创建和销毁。
10. 获取线程池
1)Executor:线程池的顶级接口。
2)ExecutorService:线程池接口,可通过submit(Runnable task)提交任务代码。
3)Executors工厂类:通过此类可以获得一个线程池。
4)通过newFixedThreadPool(int nThread)获取固定数量的线程池。参数:指定线程池中线程的数量。
5)通过newCachedThreadPool()获得动态数量的线程池,如不够则创建新的,没有上限。
10. Callable接口
(1)public interface Callable{ public V call() throws Exception; }
(2)JDK5加入,与Runnable接口类似,实现之后代表一个线程任务。
(3)Callable具有泛型返回值,可以声明异常。
11. Future接口
(1)概念:异步接受ExecutorService.submit()所返回的状态结果,当中包含了call()的返回值。
(2)方法:V get()以阻塞形式等待Future中的异步处理结果(call()的返回值)。
13. Lock锁
(1)JDK5加入,与synchronized比较,显示定义,结构更灵活。
(2)提供更多实用性方法,功能更强大、性能更优越。
(3)常用方法:1)void lock() //获取锁,如锁被占用,则等待。2)boolean tryLock() //尝试获取锁(成功返回true;失败返回false,不阻塞)。3)void unlock() //释放锁。
(4)通常与try{} finally{}一起使用,无论是否异常,最终都会释放锁。
14. 重入锁(ReentrantLock)
(1)ReentrantLock:Lock接口的实现类,与synchronized一样具有互斥锁功能。
(2)用法步骤:1)创建重入锁对象。Lock locker = new ReentrantLock();2)显示开启锁。locker.lock();3)显示释放锁。locker.unlock();4)考虑可能出现异常,释放锁必须放入finally代码块中,避免无法释放。
15. 读写锁(ReentrantReadWriteLock)
(1)一种支持一些多读的同步锁,读写分离,可分别分配读锁和写锁。
(2)支持多次分配读锁,使多个读操作可以并发执行。
(3)互斥规则:1)写–写:互斥,阻塞。2)读–写:互斥,读阻塞写,写阻塞读3)读–读:不互斥,不阻塞。4)在读操作远远高于写操作的环境中,可在保障线程安全的情况下,提高运行效率。
(4)用法:
在这里插入图片描述
16. Collections中的工具方法
(1)Collections工具中提供了多个可以获得线程安全集合的方法:在这里插入图片描述
(2)JDK1.2提供,接口同一、维护性高,但性能没有提升,均已synchronized实现。在这里插入图片描述
17. CopyOnWriteArrayList
(1)线程安全的ArrayList,加强版读写分离。
(2)写有锁,读无锁,读写之间不阻塞,优于读写锁。
(3)写入时,先copy一个容器副本、再添加新元素,最后替换引用。
(4)使用方式与ArrayList无异。
18. CopyOnWriteArraySet
(1)线程安全的Set,底层使用CopyOnWriteArrayList实现。
(2)唯一不同在于,使用addIfAbsent()添加元素,会遍历数组。
(3)如存在元素,则不添加(扔掉副本)
19. ConcurrentHashMap
(1)初始容量默认为16段(Segment),使用分段所设计。
(2)不对整个Map加锁,而是为每个Segment加锁。
(3)当多个对象存入同一个Segment时,才需要排斥。
(4)最理想的状态为16个对象分别存入16个Segment,并行数量16.(5)使用方式与HashMap无异。
20. ConcurrentLinkedQueue
(1)线程安全、可高效读写的队列,高并发下性能最好的队列。
(2)无锁。CAS比较交换算法,修改的方法包含三个核心参数(V,E,N)。
(3)V:要更新的变量;E:预期值;N:新值。
(4)只有当V == E时,V = N;否则表示已被更新过,则取消当前操作
21. BlockingQueue接口(阻塞队列)
(1)Queue的子接口,阻塞的队列,增加了两个线程状态为无限期等待的方法。
(2)方法:1)void put(E e)//将指定元素插入此队列中,如果没有可用空间,则等待。2)E take()//获取并移除此队列头部元素,如果没有可用元素,则等待。
(3)可用于解决生产者、消费者问题。
22. 阻塞队列
(1)ArrayBlockingQueue:数组结构实现,有界队列(手工固定上限)例:BlockingQueue bq = new ArrayBlockingQueue(3);
(2)LinkedBlockingQueue:链表结构实现,无界队列(默认上限Integer.MAX_VALUE)
最后,给大家附上经典问题死锁:
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值