<Java核心技术第10版>读书笔记

很乱,写给自己看的。

第3章

在这里插入图片描述
case标签可以是:
● 类型为char、byte、short或int的常量表达式。
● 枚举常量。
● 从Java SE 7开始,case标签还可以是字符串字面量。

当在switch语句中使用枚举常量时,不必在每个标签中指明枚举名,可以由switch的表达式值确定。

在这里插入图片描述
在这里插入图片描述
每一个Java应用程序都有一个带Stringarg[]参数的main方法。这个参数表明main方法将接收一个字符串数组,也就是命令行参数。

第4章

类之间的关系:
在类之间,最常见的关系有
● 依赖(“uses-a”)
● 聚合(“has-a”)
● 继承(“is-a”)
依赖(dependence),即“uses-a”关系,是一种最明显的、最常见的关系。例如,Order类使用Account类是因为Order对象需要访问Account对象查看信用状态。但是Item类不依赖于Account类,这是因为Item对象与客户账户无关。因此,如果一个类的方法操纵另一个类的对象,我们就说一个类依赖于另一个类。应该尽可能地将相互依赖的类减至最少。如果类A不知道B的存在,它就不会关心B的任何改变(这意味着B的改变不会导致A产生任何bug)。用软件工程的术语来说,就是让类之间的耦合度最小。
聚合(aggregation),即“has-a”关系,是一种具体且易于理解的关系。例如,一个Order对象包含一些Item对象。聚合关系意味着类A的对象包含类B的对象。
继承(inheritance),即“is-a”关系,是一种用于表示特殊与一般关系的。例如,Rush Order类由Order类继承而来。在具有特殊性的RushOrder类中包含了一些用于优先处理的特殊方法,以及一个计算运费的不同方法;而其他的方法,如添加商品、生成账单等都是从Order类继承来的。一般而言,如果类A扩展类B,类A不但包含从类B继承的方法,还会拥有一些额外的功能(下一章将详细讨论继承,其中会用较多的篇幅讲述这个重要的概念)。
在这里插入图片描述
UML(Unified Modeling Language,统一建模语言)绘制类图,用来描述类之间的关系。

第5章

域也可以被声明为final。对于final域来说,构造对象之后就不允许改变它们的值了。不过,如果将一个类声明为final,只有其中的方法自动地成为final,而不包括域。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
Class类实际上是一个泛型类。例如,Employee.class的类型是Class。没有说明这个问题的原因是:它将已经抽象的概念更加复杂化了。在大多数实际问题中,可以忽略类型参数,而使用原始的Class类。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第8章

在这里插入图片描述

第9章

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

第14章

多任务:同一时刻运行多个程序的能力
多进程服务:一个应用程序里有多个进程
多线程程序:可以同时运行一个以上线程的程序,即一个程序同时执行多个任务(一个任务称为一个线程(thread)。

区别:本质的区别在于每个进程拥有自己的一整套变量,而线程则共享数据

虽然听起来似乎有些风险,然而共享变量使线程之间的通信比进程之间的通信更有效、更容易。此外,在有些操作系统中,与进程相比较,线程更”轻量级“,创建、撤销一个线程比启动新进程的开销要小得多。

在实际应用中,多线程非常有用。例如,一个浏览器可以同时下载几幅图片。一个web服务器需要同时处理几个并发的请求。图形用户界面(GUI)程序用一个独立的线程从宿主操作环境中收集用户界面的时间。


1.什么是线程

这里从察看一个没有使用多线程的程序开始。用户很难让它执行多个任务。在这里插入图片描述
调用Thread.sleep不会创建一个新线程,sleep是Thread的静态方法,用于暂停当前线程的活动。
在这里插入图片描述

1.1 使用线程给其他任务提供机会

将移动球的代码放置在一个独立的线程中,运行这段代码可以提高弹跳球的响应能力。实际上,可以发起多个球,每个球都在自己的线程中运行。当用户点击Close时,事件调度线程将有机会关注到这个时间,并处理”关闭“这一动作。
如果需要执行一个比较耗时的任务,应当并发地运行任务。


单独线程中执行一个任务的简单过程:
1)将任务代码转移到了实现Runnalble接口的类的run方法中。这个接口只有一个方法:

public interface Runnable
{
	void run();
}

Runnable是一个函数式接口,可以用lambda表达式建立一个实例:

Runnable r = () -> {task code};

2)由Runnable创建一个Thread对象:

Thread t = new Thread(r);

3)启动线程:

t.start();

在这里插入图片描述
同样地。需要捕获sleep方法可能抛出的异常InterruptedException。一般情况下,线程在中断时被中止。因此,当发生InterruptedException异常时,run结束运行。

在这里插入图片描述
也可以通过构建一个Thread类的子类定义一个线程
在这里插入图片描述
然后,构造一个子类对象并调用start方法。不过这种方法已经不再推荐。应该将要并行运行的任务与运行机制解耦合。如果有很多任务,要为每个任务创建一个独立的线程所付出的代价太大了。可以用线程池解决这个问题。

警告:不要调用Thread类或Runnable对象的run方法。直接调用run方法,只会执行同一个线程中的任务,而不会启动新线程。应该调用Thread.start方法。这个方法将创建一个执行run方法的新线程。
在这里插入图片描述
在这里插入图片描述

2.中断线程

当线程的run方法执行方法体的最后一条语句后,并经由执行return语句返回时,或者出现了在方法中没有捕获的异常时,线程将终止。在java的早期版本中,还有stop方法,其他线程可以调用它终止线程,但已被弃用。

没有可以强制线程中止的方法。然而,interrupt方法可以用来请求终止线程。

对一个线程调用interrupt方法,线程的中断状态将被置位(每一个线程都具有的boolean标志)。每个线程应时不时检查这个标志,以判断线程是否被中断。

想弄清中断状态是否被置位,先调用静态的Thread.currentThread方法取得当前线程,再调用isInterrupted方法:
在这里插入图片描述
但是,如果线程被阻塞,就无法检测中断状态。这是产生InterruptedException异常的地方。当在一个被阻塞的线程(调用sleep或wait)上调用interrupt方法时,阻塞调用将被InterruptedException异常中断。(存在不能被中断的阻塞I/O调用,应该考虑选择可中断的调用。卷Ⅱ的第1章和第3章。)

某些线程很重要,以至于应该处理完异常后,继续执行,而不理会中断。但,普遍情况是线程将简单地将中断作为一个终止的请求。这种线程的run方法:
在这里插入图片描述
如果每次工作迭代后都调用sleep或其他的可中断方法,isInterrupted检测没用处。如果在中断状态被置位时调用sleep,它不会休眠。相反,它将清除这一状态(!)并抛出InterruptedException。因此,如果在循环调用sleep,不会检测中断状态。相反,要如下捕获InterruptedException异常
在这里插入图片描述
注意:interrupted是静态方法,检测当前的线程是否被中断。而且,调用它会清楚该线程中的中断状态。isInterrupted是一个实例方法,用来检验是否有线程被中断。调用它不会改变中断状态。interrupt作用是中断此线程(此线程不一定是当前线程,而是指调用该方法的Thread实例所代表的线程),但实际上只是给线程设置一个中断标志,线程仍会继续运行。
两种选择:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3.线程状态

线程可以有如下6种状态

  • New(新创建)
  • Runnable(可运行)
  • Blocked(被阻塞)
  • Waiting(等待)
  • Time waiting(计时等待)
  • Terminated(被终止)

调用getState方法确定一个线程的当前状态。

3.1 新创建线程

new Thread®,该线程还没有开始运行。状态是new。程序还没开始运行线程中的代码。运行前有一些基础工作要做。

3.2 可运行线程

调用start方法,线程处于runnable状态。一个可运行的线程可能正在运行也可能没有运行。(一个正在运行的线程也处于runnable状态)

一个线程开始运行,不必保持始终运行。运行中的线程被中断,目的是为了让其他线程获得运行机会。抢占式调度系统给每一个可运行线程一个时间片来执行任务。时间片用完,系统剥夺线程的运行权,并给另一个线程运行机会。选择下一个线程时考虑线程优先级

在这里插入图片描述
但像手机可能使用协作式调度,一个线程只有调用yield方法、或者被阻塞或等待时,线程才失去控制权。

在具有多处理器的机器,每一个处理器运行一个线程,可以有多个线程并行运行。如果线程数目>处理器数目,调度器依然采用时间片机制

3.3 被阻塞线程和等待线程

当处于这两种状态时,线程暂时不活动。不运行任何代码且消耗最少资源。直到线程调度器重新激活它。

  • 当一个线程试图获取一个内部的对象锁(而不是java.util.concurrent库中的锁),而该锁被其他线程持有,则该线程进入阻塞状态。当所有其他线程释放该锁,且线程调度器允许本线程持有它时,该线程将变为非阻塞状态
  • 当线程等待另一个线程通知调度器一个条件时,它自己进入等待状态。在调用Object.wait方法或Thread.join方法或等待java.util.concurrent库中的Lock或Condition时,就会出现这种情况。
  • 有几个方法有一个超时参数。调用它们导致线程进入计时等待(timed waiting)状态。这一状态将保持到超时期满或者接受到适当的通知。带有超时参数的方法:
    Thread.sleep
    Object.wait
    Thread.join
    Lock.tryLock
    Condition.await的计时版。

当一个线程被阻塞或等待时(或终止),另一个线程被调度为运行状态。当一个线程被重新激活(例如因为超时期满或成功获得了一个锁),调度器检查它是否具有比当前运行线程更高的优先级。如果是,调度器从当前运行线程挑选一个,剥夺其运行权,选择一个新的线程运行。
在这里插入图片描述

3.4被终止的线程

原因:

  • run方法正常退出而自然死亡
  • 一个没有捕获的异常终止了run而意外死亡

特别是,可以调用线程的stop方法杀死一个线程。该方法抛出ThreadDeath错误对象,由此杀死线程。但是方法过时了。
在这里插入图片描述
在这里插入图片描述

4.线程属性

  • 线程优先级
  • 守护线程
  • 线程组
  • 处理未捕获异常的处理器

4.1 线程优先级

每一个线程有一个优先级。默认情况下,一个线程继承它的父线程的优先级。可以用setPriority方法提高或降低任何一个线程的优先级。可以将优先级设置在MIN_PRIORITY(在Thread类中定义为1)与MAX_PRIOTITY(定义为10)之间的任何值。NORM_PRIORITY被定义为5。
线程优先级是高度依赖于系统的。Windows7个,Oracle为Linux提供的Java虚拟机,所有线程相同优先级。
在这里插入图片描述
在这里插入图片描述

4.2 守护线程

调用t.setDaemon(true);
将线程转换为守护线程(daemon thread)。唯一用途是为其他线程提供服务。
在这里插入图片描述

4.3 未捕获异常处理器

线程的run方法不能抛出任何受查异常,但,非受查异常会导致线程终止。

但不需要任何catch子句来处理可以被传播的异常。相反,在线程死亡之前,异常被传递到一个用于未捕获异常的处理器。

该处理器必须属于一个实现Thread.UncaughtExceptionHandler接口的类。单方法接口:
在这里插入图片描述
可用setUncaughtExceptionHandler为所有线程安装一个默认的处理器。
如果不为独立的线程安装处理器,此时的处理器就是该线程的ThreadGroup对象。

**注意:**线程组是一个可以统一管理的线程集合。默认情况下,创建的所有线程属于相同的线程组。

5.同步

大多数多线程应用中,两个或以上的线程需要共享对同一个数据的存取。根据各线程访问数据的次序,可能会产生讹误的对象。这样一个情况称为竞争条件(race condition)。
有两种机制防止代码块受并发访问的干扰。

  1. synchronized关键字自动提供一个锁以及相关的“条件”。
  2. 用ReentrantLock保护代码块

在这里插入图片描述
这一结构确保任何时刻只有一个线程进入临界区,一旦一个线程封锁了锁对象,其他任何线程无法通过lock语句。当其他线程调用lock时,它们被阻塞,直到第一个线程释放锁对象。

**警告:**要把解锁操作括在finally子句内。如果在临界区的代码抛出异常,锁必须被释放。否则,其他线程将永远阻塞。如果使用锁,就不能使用带资源的try语句。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值