12_并发

本文详细介绍了Java中的并发编程概念,包括线程的创建、状态、属性,如中断、守护线程、线程名和异常处理器。深入讲解了同步机制,如锁对象、条件对象、synchronized关键字以及volatile字段的作用。还涵盖了线程安全的集合、任务和线程池,以及进程的相关知识。是Java并发编程的全面指南。
摘要由CSDN通过智能技术生成

创建一个线程

在一个单独的线程中运行一个任务

将执行任务的代码放入run方法中,类要实现Runnable接口,使用lambda表达式创建实例

从这个Runnable构造一个Tread实例,然后启动线程

Runnable r=()->{
   
    ...
}
var t=new Thread(r);
t.start();

线程状态

New(新建)、Runnable(可运行)、Blocked(阻塞)、Waiting(等待)、Timed Waiting(计时等待)、Terminated(终止)

新建线程

使用new操作符新建一个新线程,但还没开始运行

可运行线程

调用了start方法的线程就处于可运行状态,可能正在运行也可能没有运行,也不一定始终保持运行

线程调度的细节依赖于操作系统提供的服务

所有桌面操作系统以及服务器操作系统都使用抢占式调度,手机等小型设备使用协作式调度

阻塞和等待线程

不运行任何代码,且消耗最少的资源

当一个线程试图获取内部的对象锁,而这个锁被其他线程占有,进入阻塞状态

当等待另一个线程通知调度器出现一个条件,进入等待状态

当调用有超时参数的方法时,进入计时等待状态

由线程调度器重新激活

当一个线程阻塞或等待时,调度另一个线程运行,当一个线程重新激活时,检查它的优先级

终止线程

当run方法正常退出,线程自然终止

当没有捕获异常而终止run方法,线程意外终止

线程属性

中断线程

没有办法可以强制线程终止

使用interrupt方法请求终止一个线程,并将线程设置为中断状态

中断解释为一个终止请求,被中断的线程可以决定如何响应中断

调用静态Tread.currentTread方法获取当前线程,然后调用isIerrupted方法检查中断状态

t.interrupt();
while(!Tread.currentTread().isIerrupted()) {
   ...}

如果线程被阻塞,就无法检查中断状态

当在一个被sleep或wait调用阻塞的线程上调用interrupt方法时,这些阻塞调用将被异常中断

当在一个被设置为中断状态的线程上调用sleep方法时,不会休眠,而是清除中断状态并抛出异常

因此在循环中调用了sleep方法,应当捕获异常,而不是检测中断状态

try
{
   
    while(...){
   Tread.sleep(delay);}
}
catch(InterruptedException){
   ...}

使用静态interrupted方法检查当前线程是否被中断,并清除中断状态

守护线程

调用setDaemon方法将一个线程转换为守护线程,用于为其他线程提供服务

当只剩下守护线程时,虚拟机就会退出

线程名

调用setName方法将字符串设置为线程的名字

可用于线程转储

未捕获异常的处理器

线程的run方法不能抛出任何检查型异常,非检查型异常可能会导致线程终止

对于可以传播的异常,没有任何catch子句,线程死亡之前,异常会传递到一个用于处理未捕获异常的处理器

处理器必须实现Tread.UncaughtExceptionHandler接口,这个接口只有一个uncaughtException方法

使用静态Tread.setUncaughtExceptionHandler方法安装一个处理器

使用静态Tread.setDefaultUncaughtExceptionHandler方法为所有线程安装一个默认处理器

如果没有安装默认处理器,则默认处理器为null,如果没有为单个线程安装处理器,那么处理器就是该线程的TreadGroup对象

线程组TreadGroup是一起管理线的程的集合,默认创建的所有线程都属于一个线程组

TreadGroup类实现了Tread.UncaughtExceptionHandler接口,它的uncaughtException方法,对有父线程组的调用父线程组的uncaughtException方法,否则调用它的非null默认处理器,否则如果Throwable是TreadDeath的实例,则什么都不做,否则将线程名以及堆栈轨迹输出到System.err

线程优先级

在java中,每个线程有一个优先级

默认一个线程会继承构造它的那个线程的优先级

调用setPriority方法设置优先级

线程的优先级极度依赖于系统,Java线程的优先级会映射到宿主机平台的优先级

在使用操作系统线程的Java版本中,不要使用线程优先级

同步

竞态条件

取决于线程访问数据的次序,可能导致对象被破坏,这称为竞态条件

在多核处理器上,或在负载很重的机器上运行大量线程,或穿插使用大量IO语句,出现破坏的风险很大

锁对象

使用ReentrantLock类保护代码块,确保任何时刻只有一个线程进入临界区,保证串行化访问

在类中创建一个静态重入锁,使多个线程共享这个锁

private var mylock = new ReentrantLock();

调用lock方法加锁,在finall子句中调用unlock方法解锁

mylock.lock();
try{
   ...}
finally
{
   
    mylock.unlock();
}

使用重入锁可以使线程反复获得已拥有的锁,被一个锁保护的代码可以调用另一个使用相同锁的方法

有一个持有计数器来跟踪对lock方法的嵌套调用,当持有计数为0时,线程释放锁

另外可以通过构造器构造一个公平锁,倾向于等待时间长的线程,但影响性能

条件对象

使用条件对象管理已经获得锁,但不能通过条件测试的线程

调用newCondition方法获得一个条件对象,一个锁对象可以关联多个条件对象

class Bank
{
   
	private Condition sufficientFunds;
    public Bank(){
   sufficientFunds = bankLock.newCondition();}
}

调用await方法暂停当前线程并放弃锁,线程进入这个条件的等待集

在任意一个线程中调用signalAll方法,激活等待这个条件的全部线程,否则进入死锁。只要一个对象的状态有变化,就调用signalAll方法

while(...)sufficientFunds.await();
...
sufficientFunds.signalAll();

使用signal方法随机选择等待集中的一个线程激活,并解除阻塞

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值