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

news2024/12/21 21:51:18

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。线程释放锁。

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32中断详述——外部EXTI

前置知识 中断:在主程序运行过程中,出现了特定的中断源,使得CPU暂停当前正在运行中的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续执行,可以参考图1所示。 图1 中断程序图 中断优先级&a…

法雷奥,百年巨头的新周期

传统汽车零部件Tier1正在加速适应全球智能化、电动化的汽车产业新变革趋势。同时,继续扩大在中国市场的投资,并强化本土化研发能力和资源投入,已经是大势所趋。 “2022年,法雷奥启动了’Move Up’计划,确定了四个符合市…

PC1 - 搭建项目

先看路由,可以查看功能模块划分。熟悉什么看什么 router文件夹下routerConfig.tsx 配置路由,创建模块文件(写好内容模块),lazy可懒加载导入。App.tsx配置一级路由,配置二级路由出口 { path:/, element: …

PTA L2-046 天梯赛的赛场安排 (25 分)

天梯赛使用 OMS 监考系统,需要将参赛队员安排到系统中的虚拟赛场里,并为每个赛场分配一位监考老师。每位监考老师需要联系自己赛场内队员对应的教练们,以便发放比赛账号。为了尽可能减少教练和监考的沟通负担,我们要求赛场的安排满…

「教程」天气预警 API 详解:申请密钥到接入代码一气呵成!

引言 天气预警 API 作为一种新型的数据接口,为开发者和应用提供了方便的获取天气预警数据的方式。通过该 API ,可以获取指定城市当前生效中的各类天气预警信息,例如暴雨、雷电、台风等。预警数据来自国家预警中心,保证了数据的高…

Linux部署人大金仓(Kingbase8)

陈老老老板🦸 👨‍💻本文专栏:国产数据库-人大金仓(kingbase8)(主要讲一些人大金仓数据库相关的内容) 👨‍💻本文简述:本文讲一下LInux上部署人大…

《计算机网络——自顶向下方法》精炼——2.3-2.4

<font color-#FFD700>“Knowledge is power” - Sir Francis Bacon 文件传输协议&#xff1a;FTP FTP协议可以在本地文件系统和远程文件系统之间传输文件。 概述 FTP在用户和服务器之间架起两条TCP连接&#xff0c;控制连接和数据连接。 控制连接&#xff1a;控制连…

[BJDCTF2020CTF]之CTFHub-Misc篇刷题记录(完结)

CTFHub-Misc篇刷题记录①wp SUCTF-2019-MISC签到题RCTF-2019-Misc-draw2020-BJDCTF-Misc-藏藏藏2020-BJDCTF-Misc-签个到2020-BJDCTF-Misc-认真你就输了2020-BJDCTF-Misc-你猜我是个啥2020-BJDCTF-Misc-一叶障目2020-BJDCTF-Misc-鸡你太美2020-BJDCTF-Misc-just a rar[BJDCTF20…

Linux下搭建Go开发环境

Linux下搭建Go开发环境可以按照以下步骤进行&#xff1a; 1、下载最新的Go语言二进制包&#xff0c;可以从官网 https://golang.org/dl/ 下载。 2、将下载好的包解压缩到你想要安装的目录下&#xff0c;如 /usr/local/go。 3、添加环境变量&#xff0c;在终端中输入以下命令…

Matplotlib 绘图标记

Matplotlib 绘图标记 绘图过程如果我们想要给坐标自定义一些不一样的标记&#xff0c;就可以使用 plot() 方法的 marker 参数来定义。 以下实例定义了实心圆标记&#xff1a; 实例 import matplotlib.pyplot as plt import numpy as npypoints np.array([1,3,4,5,8,9,6,1,3…

【信息安全】一文读懂 “3保1评” 等保、分保、关保、密评

【前言】 信息安全知识大而杂&#xff0c;网上资料参差不齐&#xff0c;相关概念模糊不清&#xff0c;所以想归纳一些知识点&#xff0c;与各位共勉。 本篇博文介绍国内安全领域常见的“3保1评”&#xff0c;即等保&#xff08;网络安全等级保护&#xff09;、分保&#xff08;…

[ Java SE] 对象的比较

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点!人生格言&#xff1a;当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友一起加油喔&#x1f9be;&am…

Postgres逻辑复制详解

逻辑复制 逻辑复制&#xff08;Logical Replication&#xff09;&#xff0c;是一种根据数据对象的 复制标识&#xff08;Replica Identity&#xff09;&#xff08;通常是主键&#xff09;复制数据对象及其变化的方法。 逻辑复制 这个术语与 物理复制相对应&#xff0c;物理…

不得不说的结构型模式-适配器模式

适配器模式&#xff08;Adapter Pattern&#xff09;是结构型模式之一&#xff0c;它将一个类的接口转换成客户希望的另一个接口&#xff0c;从而使原本由于接口不兼容而不能一起工作的类能够协同工作。适配器模式包括对象适配器和类适配器两种实现方式。 在对象适配器中&#…

Ae 入门系列之十:效果和动画预设

Ae 中提供了丰富的效果 Effects和动画预设 Animation Presets&#xff0c;可以轻松、快速地创建出各种酷炫的动画。 ◆ ◆ ◆ 效果 添加效果 方法一&#xff1a;先选中一个或多个图层&#xff0c;然后在Ae菜单&#xff1a;效果 Effect中找到并添加需要的效果。 方法二&#x…

什么是gpt一4-如何用上gpt-4

怎么使用gpt-4 目前GPT-4还未正式发布或公开&#xff0c;因此也没有详细的对接说明。但是我们可以根据GPT-4的前身GPT-3的应用经验&#xff0c;以及GPT-4的预期功能推测一些可能的使用步骤&#xff1a; 选择适合的GPT-4实现技术&#xff1a;GPT-4可能有不同的实现技术&#xff…

Allegro PCB后处理

Allegro PCB后处理&#xff0c;主要是完成线路设计以后&#xff0c;输出生产文件之前的处理。这是看教程做的记录&#xff0c;方便以后自己参考。 教程&#xff1a; [小哥Cadence Allegro 132讲字幕版PCB视频教程]_哔哩哔哩_bilibili 感觉关键是多看右边Options菜单&#xff0…

nodejs+python+php+springboot+vue 校园快递代取配送系统

管理员的主要功能有&#xff1a; 1.管理员输入账户登陆后台 2.个人中心&#xff1a;管理员修改密码和账户信息 3.用户管理&#xff1a;对注册的用户信息进行删除&#xff0c;查询&#xff0c;添加&#xff0c;修改 4.配送员管理&#xff1a;对配送员信息进行添加&#xff0c;修…

力扣刷题——移除元素

1、移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中…

【模拟IC】版图的基础操作和基础知识总结(1)

今天总结一下在画版图使用的基本操作和遇到的问题及解决方法。# 一、基本操作 &#xff08;1&#xff09;首先是使用layout XL的优势是可以对应原理图的器件&#xff0c;这样方便我们画版图。 &#xff08;2&#xff09;快捷键的操作&#xff1a; F 进行整体版图的居中 K 就是…