异常

分类

  • 编译时期异常:checked异常。

    在编译时期,就会检查,如果没有处理异常,则编译失败。(如日期格式化异常)

  • 运行时期异常:runtime异常。

    在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)。(如数学异常)

处理

五个关键字:try,catech,finally,throw,throws

捕获异常try…catch

  1. try{
  2. 编写可能会出现异常的代码
  3. }catch(异常类型 e){
  4. 处理异常的代码
  5. //记录日志/打印异常信息/继续抛出异常
  6. }

finally 代码块

  1. try...catch....finally:自身需要处理异常,最终还得关闭资源。

抛出异常throw

  1. throw new 异常类名(参数);

声明异常throws

  1. 修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }

自定义异常

在开发中根据自己业务的异常情况来定义异常类

  1. 自定义一个编译期异常: 自定义类 并继承于

    java.lang.Exception
  2. 自定义一个运行时期的异常类:自定义类 并继承于

    java.lang.RuntimeException

try自动关闭资源

Java 7增强了try语句的功能————它允许在try关键字后跟一对圆括号,圆括号可以声明,初始化一个或多个资源,此处的资源指得是那些必须在程序结束时必须关闭的资源(比如数据库连接,网络连接等),try语句在该语句结束时自动关闭这些资源。

为了保证try语句可以正常关闭资源,这些资源实现类必须实现Closeable或AutoCloseable接口,实现这些类就必须实现close方法。

多线程

并发与并行

  1. 并发:指两个或多个事件在同一段时间内发生
  2. 并行:指两个或多个事件在同一时刻发生(同时发生)

线程与进程

  1. 进程:指一个内存存中的运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程
  2. 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程,一个进程中是可以有多个线程的,这个应用程序也可称之为多线程程序
  3. 简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程

创建并启动多线程的步骤

方式一

  1. 定义Thread 类的子类,并重写该类的run()方法,该run()方法的方法体就代表了线程需要完成的任务,因此把run()方法称为线程执行体
  2. 创建Thread 子类的实例,即创建了线程对象
  3. 调用线程对象的start()方法来启动该线程

方式二

  1. 定义Runnable接口的实现类,并重写该接口的run()方法 ,该run()犯法的方法体同样是该线程的线程执行体
  2. 创建Runnable 实现类的实例,并以此实例作为Threadtarget 来创建Thread 对象,该Thread 对象才是真正的线程对象
  3. 调用线程对象的start()方法来启动线程

匿名内部类方式实现线程的创建

使用线程的匿名内部类方式,可以方便的实现每个线程执行不同的线程任务操作。

使用匿名内部类的方式实现Runnable接口,重写Runnable接口中的run方法:

  1. new Thread(new Runnable(){
  2. @Override
  3. public void run {
  4. //...
  5. }
  6. }).start();

Thread和Runnable的区别

实现Runnable接口比继承Thread类所具有的优势:

  1. 适合多个相同的程序代码的线程去共享同一个资源
  2. 可以避免Java中的单继承的局限性
  3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立
  4. 线程池只能放入实现RunnableCallable 类线程,不能直接放入继承Thread 的类

线程同步

  1. 同步代码块

    synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

    1. synchronized(同步锁){需要同步操作的代码 }
  2. 同步方法

    使用synchronized 修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。

    1. public synchronized void method(){ 可能会产生线程安全问题的代码 }
  3. 锁机制(Lock锁)

java.util.concurrent.locks.Lock 机制提供了比synchronized 代码块和synchronized 方法更广泛的锁定操作, 同步代码块/同步方法具有的功能Lock 都有,除此之外更强大,更体现面向对象

  1. public void lock() :加同步锁
  2. public void unlock() :释放同步锁

等待唤醒机制

线程间通信

多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同

为什么要处理线程间通信

多个线程并发执行时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行, 那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据。

如何保证线程间通信有效利用资源

多个线程在处理同一个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同一个变量的使用或操作。 就是多个线程在操作同一份数据时, 避免对同一共享变量的争夺。也就是我们需要通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。

等待唤醒机制

什么是等待唤醒机制

这是多个线程间的一种协作机制。谈到线程我们经常想到的是线程间的竞争(race),比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制。就好比在公司里你和你的同事们,你们可能存在在晋升时的竞争,但更多时候你们更多是一起合作以完成某些任务。

就是在一个线程进行了规定操作后,就进入等待状态(wait()), 等待其他线程执行完他们的指定代码过后 再将其唤醒(notify());在有多个线程进行等待时, 如果需要,可以使用 notifyAll()来唤醒所有的等待线程。

wait/notify 就是线程间的一种协作机制。

等待唤醒中的方法

等待唤醒机制就是用于解决线程间通信的问题的,使用到的3个方法的含义如下:

  1. wait:线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁了,这时的线程状态即是 WAITING。它还要等着别的线程执行一个特别的动作,也即是“通知(notify)”在这个对象上等待的线程从wait set 中释放出来,重新进入到调度队列(ready queue)中
  2. notify:则选取所通知对象的 wait set 中的一个线程释放;例如,餐馆有空位置后,等候就餐最久的顾客最先入座。
  3. notifyAll:则释放所通知对象的 wait set 上的全部线程。

注意:

哪怕只通知了一个等待的线程,被通知线程也不能立即恢复执行,因为它当初中断的地方是在同步块内,而此刻它已经不持有锁,所以她需要再次尝试去获取锁(很可能面临其它线程的竞争),成功后才能在当初调用 wait 方法之后的地方恢复执行。

总结如下:

  • 如果能获取锁,线程就从 WAITING 状态变成 RUNNABLE 状态;
  • 否则,从 wait set 出来,又进入 entry set,线程就从 WAITING 状态又变成 BLOCKED 状态

调用wait和notify方法需要注意的细节

  1. wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。
  2. wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。
  3. wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方法。

生产者与消费者问题

包子铺线程生产包子,吃货线程消费包子。当包子没有时(包子状态为false),吃货线程等待,包子铺线程生产包子(即包子状态为true),并通知吃货线程(解除吃货的等待状态),因为已经有包子了,那么包子铺线程进入等待状态。接下来,吃货线程能否进一步执行则取决于锁的获取情况。如果吃货获取到锁,那么就执行吃包子动作,包子吃完(包子状态为false),并通知包子铺线程(解除包子铺的等待状态),吃货线程进入等待。包子铺线程能否进一步执行则取决于锁的获取情况。

代码

包子资源类:

  1. public class BaoZi {
  2. String pier ;
  3. String xianer ;
  4. boolean flag = false ;//包子资源状态
  5. }

吃货线程类:

  1. public class ChiHuo extends Thread{
  2. private BaoZi bz;
  3. public ChiHuo(String name,BaoZi bz){
  4. super(name);
  5. this.bz = bz;
  6. }
  7. @Override
  8. public void run() {
  9. while(true){
  10. synchronized (bz){
  11. if(bz.flag == false){//没包子
  12. try {
  13. bz.wait();
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. }
  17. }
  18. System.out.println("吃货正在吃"+bz.pier+bz.xianer+"包子");
  19. bz.flag = false;
  20. bz.notify();
  21. }
  22. }
  23. }
  24. }

包子铺线程类:

  1. public class BaoZiPu extends Thread {
  2. private BaoZi bz;
  3. public BaoZiPu(String name,BaoZi bz){
  4. super(name);
  5. this.bz = bz;
  6. }
  7. @Override
  8. public void run() {
  9. int count = 0;
  10. //造包子
  11. while(true){
  12. //同步
  13. synchronized (bz){
  14. if(bz.flag == true){//包子资源 存在
  15. try {
  16. bz.wait();
  17. } catch (InterruptedException e) {
  18. e.printStackTrace();
  19. }
  20. }
  21. // 没有包子 造包子
  22. System.out.println("包子铺开始做包子");
  23. if(count%2 == 0){
  24. // 冰皮 五仁
  25. bz.pier = "冰皮";
  26. bz.xianer = "五仁";
  27. }else{
  28. // 薄皮 牛肉大葱
  29. bz.pier = "薄皮";
  30. bz.xianer = "牛肉大葱";
  31. }
  32. count++;
  33. bz.flag=true;
  34. System.out.println("包子造好了:"+bz.pier+bz.xianer);
  35. System.out.println("吃货来吃吧");
  36. //唤醒等待线程 (吃货)
  37. bz.notify();
  38. }
  39. }
  40. }
  41. }

测试类:

  1. public class Demo {
  2. public static void main(String[] args) {
  3. //等待唤醒案例
  4. BaoZi bz = new BaoZi();
  5. ChiHuo ch = new ChiHuo("吃货",bz);
  6. BaoZiPu bzp = new BaoZiPu("包子铺",bz);
  7. ch.start();
  8. bzp.start();
  9. }
  10. }

执行效果:

  1. 包子铺开始做包子
  2. 包子造好了:冰皮五仁
  3. 吃货来吃吧
  4. 吃货正在吃冰皮五仁包子
  5. 包子铺开始做包子
  6. 包子造好了:薄皮牛肉大葱
  7. 吃货来吃吧
  8. 吃货正在吃薄皮牛肉大葱包子
  9. 包子铺开始做包子
  10. 包子造好了:冰皮五仁
  11. 吃货来吃吧
  12. 吃货正在吃冰皮五仁包子

线程池

容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源

好处

  1. 降低资源消耗。减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
  2. 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  3. 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

使用

Java里面线程池的顶级接口是java.util.concurrent.Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是java.util.concurrent.ExecutorService

要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在java.util.concurrent.Executors线程工厂类里面提供了一些静态工厂,生成一些常用的线程池。官方建议使用Executors工程类来创建线程池对象。

Executors类中有个创建线程池的方法如下:

  • public static ExecutorService newFixedThreadPool(int nThreads):返回线程池对象。(创建的是有界线程池,也就是池中的线程个数可以指定最大数量)

获取到了一个线程池ExecutorService 对象,那么怎么使用呢,在这里定义了一个使用线程池对象的方法如下:

  • public Future<?> submit(Runnable task):获取线程池中的某一个线程对象,并执行

    Future接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用。

使用线程池中线程对象的步骤

  1. 创建线程池对象。
  2. 创建Runnable接口子类对象。(task)
  3. 提交Runnable接口子类对象。(take task)
  4. 关闭线程池(一般不做)。

Runnable实现类代码:

  1. public class MyRunnable implements Runnable {
  2. @Override
  3. public void run() {
  4. System.out.println("我要一个教练");
  5. try {
  6. Thread.sleep(2000);
  7. } catch (InterruptedException e) {
  8. e.printStackTrace();
  9. }
  10. System.out.println("教练来了: " + Thread.currentThread().getName());
  11. System.out.println("教我游泳,交完后,教练回到了游泳池");
  12. }
  13. }

线程池测试类:

  1. public class ThreadPoolDemo {
  2. public static void main(String[] args) {
  3. // 创建线程池对象
  4. ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
  5. // 创建Runnable实例对象
  6. MyRunnable r = new MyRunnable();
  7. //自己创建线程对象的方式
  8. // Thread t = new Thread(r);
  9. // t.start(); ---> 调用MyRunnable中的run()
  10. // 从线程池中获取线程对象,然后调用MyRunnable中的run()
  11. service.submit(r);
  12. // 再获取个线程对象,调用MyRunnable中的run()
  13. service.submit(r);
  14. service.submit(r);
  15. // 注意:submit方法调用结束后,程序并不终止,是因为线程池控制了线程的关闭。
  16. // 将使用完的线程又归还到了线程池中
  17. // 关闭线程池
  18. //service.shutdown();
  19. }
  20. }

JavaSE复习(三)异常与多线程的更多相关文章

  1. JavaSE复习_7 异常

    △子父类涉及的异常问题:      1.子类在覆盖方法时,父类的方法如果抛出了异常,那么子类的方法只能抛出父类的异常或者该异常的子类,且只能抛出异常的子集      2.如果父类抛出了多个异常,子类只 ...

  2. javaSE高级篇1 — 异常与多线程基础

    1.异常的体系结构  注:Throwable是一个类,不是一个接口,这个类里面是描述的一些Error和Exception的共性,如图所示: 异常 / 错误是什么意思? 定义:指的是程序运行过程中,可能 ...

  3. Java基础复习笔记系列 八 多线程编程

    Java基础复习笔记系列之 多线程编程 参考地址: http://blog.csdn.net/xuweilinjijis/article/details/8878649 今天的故事,让我们从上面这个图 ...

  4. javaSE复习之——线程

    线程其实就是程序执行的一条路径,一个进程中可以包含多条线程,多线程并发执行可以提高程序效率,可以同使完成多项任务 多线程的应用场景 迅雷多线程一起下载 服务器同时处理多个客户请求 多线程原理(单核CP ...

  5. JavaSE复习_10 多线程复习

    △wait()和sleep()的区别:  1.wait():没有等待时间,而sleep()需要有等待时间作为参数.  2.在同步中对于CPU的执行权和锁的处理不同:   wait()会释放执行权和锁. ...

  6. JavaSE复习日记 : 算是个小前言吧

    /* * Java也学了好久了,抽个时间整理了一下课堂笔记,也有些是我刚开始学会犯的一些错误.在这里浅谈一下JavaSE的基础内容,对我来说也是一种不错的复习方式. * * 那好,对于初学者来说,学习 ...

  7. javaSE复习总结

    之前匆匆忙忙学完了java,后来又接着学习ee,然而,越是想要快一点最后反而会更慢一点.因为匆忙间 我几乎什么都没学会.在后面的学习中实在非常吃力.就把javase 的视频大部分又重新看了一遍.真的收 ...

  8. ArrayList的ConcurrentModificationException异常和多线程下的异常

    一.ConcurrentModificationException ArrayList源码看为什么出现异常: public class ArrayList<e> extends Abstr ...

  9. C++复习8.异常处理和RTTI

    C++异常处理和RTTI技术 20130930 1.异常处理的基本知识 C语言中是没有内置运行时错误处理机制,对于错误发生的时候使用的几种处理机制: 函数返回彼此协商后统一定义的状态编码来表示操作成功 ...

随机推荐

  1. spring入门(八) spring mvc设置默认首页

    1.web.xml配置如下 <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3// ...

  2. swift计算label动态宽度和高度

    swift计算label动态宽度和高度 func getLabHeigh(labelStr:String,font:UIFont,width:CGFloat) -> CGFloat { let ...

  3. [USACO11OPEN]奶牛跳棋Cow Checkers(博弈论)

    题目描述 One day, Bessie decides to challenge Farmer John to a game of 'Cow Checkers'. The game is playe ...

  4. 一、spring 4概述

    0 前言 0.0 Spring 来历 Spring 是于2003年兴起的一个轻量级的Java 开发框架, 为了解决企业应用开发的复杂性而创建, 核心是控制反转(IoC)和面向切面编程(AOP). 简单 ...

  5. 快速玩转linux(3)

    Linux常用命令 软件操作命令 执行操作 命令 软件包管理器 yum 安装软件 yum install xxx 卸载软件 yum remove xxx 搜索软件 yum search xxx 清除缓 ...

  6. conda 安装 graph-tool, 无需编译

    1. 添加以下channels到~/.condarc $ conda config --add channels conda-forge $ conda config --add channels o ...

  7. struts2的token interceptor

    关于struts2的token拦截器的说明 原理:struts2的token interceptor是关于重复提交的拦截器,其实现是:在form表单中加入token标签,如下: <form ac ...

  8. maven-聚合与继承

    1.聚合-方便快速构建项目 多个maven模块要构建需要分别执行一次maven构建命令,怎样只执行一次构建命令就构建多个maven模块呢?maven提供了聚合模块可以满足一次运行,构建多模块的要求 2 ...

  9. php-语言参考-类型3.2-未完待续

    一,PHP变量的8个类型 四种标量类型: boolean (布尔型) integer (整型) float (浮点型, 也称作 double) string (字符串) 两种复合类型: array ( ...

  10. 使用MapReduce读取HBase数据存储到MySQL

    Mapper读取HBase数据 package MapReduce; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hba ...