Java核心技术 卷1-总结-16

Java核心技术 卷1-总结-16

  • 线程属性
    • 线程优先级
    • 守护线程
    • 未捕获异常处理器
  • 同步
    • 竞争条件的一个例子
    • 竞争条件详解
    • 锁对象

线程属性

线程的各种属性包括:线程优先级、守护线程、线程组以及处理未捕获异常的处理器。

线程优先级

在Java程序设计语言中,每一个线程有一个优先级。默认情况下,一个线程继承它的父线程的优先级。每当线程调度器有机会选择新线程时,它首先选择具有较高优先级的线程。

守护线程

可以通过调用

t.setDaemon(true);

将线程转换为守护线程(daemon thread)。守护线程的唯一用途是为其他线程提供服务。 计时线程就是一个例子,它定时地发送"计时器嘀嗒"信号给其他线程或清空过时的高速缓存项的线程。当只剩下守护线程时,虚拟机就退出了,由于如果只剩下守护线程,就没必要继续运行程序了。守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。

未捕获异常处理器

**线程的run方法不能抛出任何受查异常,但是,非受查异常会导致线程终止。在这种情况下,线程就死亡了。**但是,不需要任何catch子句来处理可以被传播的异常。相反,就在线程死亡之前,异常被传递到一个用于未捕获异常的处理器。

该处理器必须属于一个实现Thread.UncaughtExceptionHandler接口的类。这个接口只有一个方法。

void uncaughtException(Thread t, Throwable e)

可以用setUncaughtExceptionHandler方法为任何线程安装一个处理器。也可以用Thread 类的静态方法setDefaultUncaughtExceptionHandler为所有线程安装一个默认的处理器。替换处理器可以使用日志API发送未捕获异常的报告到日志文件。

同步

在大多数实际的多线程应用中, 两个或两个以上的线程需要共享对同一数据的存取。如果两个线程存取相同的对象,并且每一个线程都调用了一个修改该对象状态的方法,这时根据各线程访问数据的次序,可能会产生讹误的对象。这样一个情况通常称为竞争条件(race condition)。

竞争条件的一个例子

为了避免多线程引起的对共享数据的讹误,必须学习如何同步存取。

在下面的测试程序中,模拟一个有若干账户的银行。随机地生成在这些账户之间转移钱款的交易。每一个账户有一个线程。每一笔交易中,会从线程所服务的账户中随机转移一定数目的钱款到另一个随机账户。

模拟代码具有transfer方法的Bank类。该方法从一个账户转移一定数目的钱款到另一个账户。如下是Bank类的transfer方法的代码。

public void transfer(int from, int to, double amount) {
	// CAUTION: unsafe when called from multiple threads \
	System.out.print(Thread.currentThread());
	accounts[from] -= amount;
	System.out.printf("%10.2f from %d to %d",amount, from, to);
	accounts[to] += amount;
	System.out.printf("Total Balance:%10.2f%n", getTotalBalance());
}

这里是Runnable类的代码。它的run方法不断地从一个固定的银行账户取出钱款。在每一次迭代中,run方法随机选择一个目标账户和一个随机账户,调用bank对象的transfer方法,然后睡眠。

Runnable r = () -> {
	try {
		while(true) {
			int toAccount=(int)(bank.size() * Math.random();
			double amount = MAX_AMOUNT * Math.random();
			bank.transfer(fromAccount, toAccount, amount);
			Thread.sleep((int)(DELAY * Math.random());
			}
		}	
	catch (InterruptedException e)
	{
	}
};

当这个模拟程序运行时,不清楚在某一时刻某一银行账户中有多少钱。但是,知道所有账户的总金额应该保持不变,因为所做的一切不过是从一个账户转移钱款到另一个账户。

在每一次交易的结尾,transfer方法重新计算总值并打印出来。本程序永远不会结束。只能手动终止这个程序。下面是程序的输出:

Thread[Thread-11,5,main] 588.48 from 11 to 44 Total Balance: 100000.00
Thread[Thread-12,5,main] 976.11 from 12 to 22 Total Balance: 100000.00
Thread[Thread-14,5,main] 521.51 from 14 to 22 Total Bal ance: 100000.00
Thread[Thread-13,5,main] 359.89 from 13 to 81 Total Bal ance: 100000.00
...
Thread[Thread-36,5,main] 401.71 from 36 to 73 Total Balance:  99291.06
Thread[Thread-35,5,main] 691.46 from 35 to 77 Total Bal ance:   99291.06
Thread[Thread-37,5,main] 78.64 from 37 to 3 Total Balance:   99291.06
Thread[Thread-34,5,main] 197.11 from 34 to 69 Total Balance:   99291.06
Thread[Thread-36,5,main] 85.96 from 36 to 4 Total Balance:   99291.06

正如前面所示,出现了错误。在最初的交易中,银行的余额保持在$100000,这是正确的,因为共100个账户,每个账户$1000。但是,过一段时间,余额总量有轻微的变化。当运行这个程序的时候,会发现有时很快就出错了,有时很长的时间后余额发生混乱。这样的状态不会带来信任感。

竞争条件详解

上述的程序,其中有多个线程更新银行账户余额。一段时间之后,错误就会出现,总额要么增加,要么变少。当两个线程试图同时更新同一个账户的时候,这个问题就有可能出现。假定两个线程同时执行指令

accounts[to] += amount;

问题在于这不是原子操作。该指令可能被处理如下:

  • accounts[to]加载到寄存器。
  • 增加 amount。
  • 将结果写回accounts[to]

现在,假定第1个线程执行步骤1和2,然后,它被剥夺了运行权。假定第2个线程被唤醒并修改了accounts数组中的同一项。然后,第1个线程被唤醒并完成其第3步。这样,这一动作擦去了第二个线程所做的更新。于是,总金额不再正确。

在这里插入图片描述
transfer方法的执行过程中可能会被中断。如果能够确保线程在失去控制之前方法运行完成, 那么银行账户对象的状态永远不会出现讹误。

锁对象

有两种机制防止代码块受并发访问的干扰。Java语言提供一个synchronized关键字达到这一目的,并且Java SE 5.0引人了ReentrantLock类。synchronized关键字自动提供一个锁以及相关的"条件",对于大多数需要显式锁的情况,这是很便利的。 用ReentrantLock保护代码块的基本结构如下:

myLock.lock();// a ReentrantLock object 
try {
	critical section 
}
finally {
	myLock.unlock();// make sure the lock is unlocked even if an exception is thrown ”
}

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

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

使用锁来保护Bank类的transfer方法。

public class Bank {
	private Lock bankLock = new ReentrantLock();// ReentrantLock implements the Lock interface 
	public void transfer(int from, int to, int amount) {
		bankLock.lock();
		try {
			System.out.print(Thread.currentThread();
			accounts[from] -= amount;
			System.out.printf("%10.2f from %d to %d", amount, from, to);
			accounts[to] += amount;
			System.out.printf("Total Balance:%10.2f%n",getTotalBalance());
		}
		finally {
		bankLock.unlock();
		}
	}
}

**假定一个线程调用transfer,在执行结束前被剥夺了运行权。假定第二个线程也调用transfer,由于第二个线程不能获得锁,将在调用lock方法时被阻塞。它必须等待第一个线程完成transfer方法的执行之后才能再度被激活。当第一个线程释放锁时,那么第二个线程才能开始运行。**如下图:
在这里插入图片描述

添加加锁代码到transfer方法并且再次运行程序。可以永远运行它,而银行的余额不会出现讹误。

注意每一个Bank对象有自己的ReentrantLock对象。如果两个线程试图访问同一个Bank 对象,那么锁以串行方式提供服务。但是,如果两个线程访问不同的 Bank 对象,每一个线程得到不同的锁对象,两个线程都不会发生阻塞。本该如此,因为线程在操纵不同的Bank实例的时候,线程之间不会相互影响。

锁是可重入的,因为线程可以重复地获得已经持有的锁。锁保持一个持有计数(hold count)来跟踪对lock方法的嵌套调用。线程在每一次调用lock都要调用unlock来释放锁。 由于这一特性,被一个锁保护的代码可以调用另一个使用相同的锁的方法。

例如,transfer方法调用getTotalBalance方法,这也会封锁 bankLock对象,此时 bankLock 对象的持有计数为2。当getTotalBalance方法退出的时候,持有计数变回1。当transfer方法线程1退出的时候, 持有计数变为 0。线程释放锁。

通常, 可能想要保护需若干个操作来更新或检查共享对象的代码块。要确保这些操作完成后, 另一个线程才能使用相同对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/14574.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenGL入门教程之 纹理

引言 我们已经了解到,我们可以为每个顶点添加颜色来增加图形的细节,从而创建出有趣的图像。但是,如果想让图形看起来更真实,我们就必须有足够多的顶点,从而指定足够多的颜色。这将会产生很多额外开销,因为每…

ChatGPT国内可用版-国内chatGPT哪个软件好用

国内chatGPT哪个软件最好用 国内对接ChatGPT软件,让智能的对话变得更加简单便捷!ChatGPT是由OpenAI公司开发的最新一代自然语言处理技术,为聊天机器人赋予了更加真实、流畅、智能的语言表达能力。 我们是国内一家专注于人工智能和自然语言处…

旧版VS安装 Visual Studio 2019/2017/2015官方安装教程

安装VisualStudio找不到官方版本?只能找到第三方?害怕中毒? 不要急,本文例举了VS 2019 2017 2015的官方位置,不用但心装成第三方Visual Studio 百度搜索 Visual Studio 2017,只有第三方的包,而…

大孔树脂型号,A-722,ADS500,ADS600,ADS750,ADS800

一、产品介绍 基于吸附功能的聚苯乙烯特种树脂 Tulsimer ADS-600 是一款没有离子官能基的,由交联聚苯乙烯合成的功能强大的吸附型树脂。 Tulsimer ADS-600 主要应用于水溶液中吸附酚及其化合物,氯代烃等含氯物质,表面活性剂&#xff0…

Three——二、加强对三维空间的认识

Three——二、加强对三维空间的认识 接上个例子我们接着往下看 辅助观察坐标系 THREE.AxesHelper()的参数表示坐标系坐标轴线段尺寸大小,你可以根据需要改变尺寸。 使用方法: // AxesHelper:辅助观察的坐标系 const axesHelper new THRE…

java的社区养老服务系统 ssm空巢老人

创新点: 1、根据时间、类型统计用户下单记录,形成可视化图形(饼状图) 2、根据用户爱好推荐项目 包含模块:关于我们、联系我们、外链信息、资讯类型、服务资讯、服务类型、服务项目、案例类型、服务案例、讨论类型、讨论…

【数据库】— 2NF、3NF、BCNF、最小函数依赖集例题

判断范式级别 设有关系模式W(C,P,S,G,T,R),其中各属性的含义是:C课程,P教师,S学生,G成绩,T时间,R教室,根据定义有如下数据依赖集 D{ C→P,(S,C)→G,(T,R)→C&…

2023.04.23 学习周报

文章目录 摘要文献阅读1.题目2.摘要3.介绍4.模型4.1 研究区域4.2 自相关分析4.3 LSTM 5.实验与讨论5.1 高架道路不同位置空气污染物的变化5.2 高架道路不同位置空气污染物的相关性5.3 高架道路不同位置空气污染物预测 6.结论7.展望 度规张量1.曲率2.度量张量3.代码实现4.平行四…

【go】三色标记-垃圾回收机制

垃圾回收原因 : 垃圾回收是一种内存管理技术,它的主要目的是自动管理程序中的内存分配和释放,以减少内存泄漏和野指针等问题 赋值器与回收器: 赋值器(Mutator)是指程序中的执行部分,负责创建…

LinkedBlockingQueue原理

1. 基本的入队出队 public class LinkedBlockingQueue<E> extends AbstractQueue<E>implements BlockingQueue<E>, java.io.Serializable {static class Node<E> {E item;/*** 下列三种情况之一* - 真正的后继节点* - 自己, 发生在出队时* - null, 表…

Django框架之创建项目、应用并配置数据库

django3.0框架创建项目、应用并配置数据库 创建项目 进入命令行 新建一个全英文的目录 进入目录 输入命令 django-admin startproject project 项目目录层级 查看当前目录层级 tree /f 目录文件说明 创建数据库 做一个学生管理系统做演示&#xff0c;使用navicat创建数据…

windows中vscode配置C/C++环境

首先要把MinGW的环境安装完&#xff0c;我一般是下载带有MinGW的codeblocks&#xff0c;这样省去自己安装MinGW。因为安装MinGW还挺麻烦的。 安装完codeblocks&#xff0c;找到其安装目录&#xff0c;把bin文件配置到环境变量去&#xff1a; 将bin添加到环境变量 然后打开vsco…

[读书笔记] 从问题和公式角度理解 Diffusion Model

[小全读书笔记] 从问题和公式角度理解 Diffusion Model 1. Diffusion Model的结构1.1 定义与限制1.2 定义与限制的数学体现 2. Diffusion Model的模型训练2.1 似然函数转换成ELBO2.2 拆解ELBO2.3 求解关键&#xff1a; q ( x t − 1 ∣ x t , x 0 ) q(x_{t-1}|x_t,x_0) q(xt−1…

【c语言】函数的数据传递原理 | 数组传入函数方法

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…

ChatGPT实现语义分析情感分类

语义分析情感分类 我们从开源社区找到了中科院谭松波博士整理的携程网酒店评论数据集(https://raw.githubusercontent.com/SophonPlus/ChineseNlpCorpus/master/datasets/ChnSentiCorp_htl_all/ChnSentiCorp_htl_all.csv)。一共七千余条数据&#xff0c;包括 label 和 review …

5G基站外市电改造建设方案 (ppt可编辑)

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除 外市电定义及分类 定义&#xff1a;由供电部门提供的专用高压电源或非专用高压电源或低压电源均称为市电。分类&#xff1a; &#xff08;1&#xff09;按电压等级分类 ①提供…

Linux Shell 实现一键部署http+用户名密码登录

Apache 前言 Apache(音译为阿帕奇)是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上&#xff0c;由于其跨平台和安全性被广泛使用&#xff0c;是最流行的Web服务器端软件之一。它快速、可靠并且可通过简单的API扩充&#xff0c;将Perl/Python等…

西交大-一百本书-解决不能粘贴的限制

快毕业了&#xff0c;要填四个一百&#xff0c;其他三个都几分钟就填完了。只有读一百本书要写读书笔记且不能粘贴&#xff0c;防谁呢真是的。发现一种解决不能粘贴限制的方法。顺道附上利用ChatGpt快速生成书评的方法。 四个一百网址 一、 解除粘贴限制 以edge浏览器为例 登…

Redis基础知识概述

Redis基础知识概述 文章目录 Redis基础知识概述一、Redis简介二、NoSQL技术三、Redis的高并发和快速原因四、Redis为什么是单线程的 五、单线程的优劣势1、优势2、劣势 六、Redis高并发总结七、在java中使用Redis1、添加Jedis依赖 八、Redis在Java Web中的应用1、存储缓存用的数…

C++的异常

文章目录 1. C语言传统的处理错误的方式2. C异常概念3. 异常的使用3.1 异常的抛出和匹配原则 4. C标准库的异常体系5. 自定义异常体系6. 异常的重新抛出7. 函数调用链中异常栈展开匹配原则8. 异常安全9. 异常规范10. 异常的优缺点 1. C语言传统的处理错误的方式 传统的错误处理…