Java线程与锁-1

1 前言

在JVM运行环境中,单线程的行为是同时只有一个线程执行代码中的一个语句或者一个表达式。多线程的行为是同时多个线程执行代码中的一个语句或者一个表达式,也就是,这些线程独立地执行同一段代码并且操作位于同一个共享主内存区域中的值或对象,而这些多线程的运行机制需要硬件与操作系统使用多核处理器与时间片的轮询共同实现。

多个线程同时执行任务的行为性质并称之为并发性,多线程的运行方式被称之为并行机制。

在Java语言语法中线程类的名称是Thread,用户可以使用Thread类创建一个或者多个线程实例,然后调用Thead类实例的start方法启动线程的执行。

JVM提供多线程之间协作的锁机制,该机制能保证在多线程执行环境中处于共享内存区域中的值与对象能安全地、正确地被读写。

本章节主要描述Java程序语言设计中有关多线程并发编程的内存可见性的语法语义,该语法语义被称之为Java程序语言的内存模型。

内存模型中的语法语义并不是规定多线程代码应该如何地被运行,而是规定多线程代码被运行时应该具有的正确行为,也就是,只要保证行为正确,任何运行代码的策略都可行。因此,JVM也提供很多有关多线程的优化机制,该机制能保证行为正确的前提下,提供高性能的并发编程模型。

2 Synchronization

Synchronization中文表示的是同步,是指一种同步锁机制,Java编程语言提供并用于多线程之间的协作与交互,最基本的实现方式是在代码中使用同步方法或者同步块,其实现原理是使用监听器(monitor)。每个Java实例对象O都与一个监听器M绑定,任何一个线程都具有权限锁定或者解锁O对应的监听器M,而在多线程运行环境中,同时只能有一个线程锁定O对应的监听器M,其他线程只能阻塞等待直到获取到O对应的监听器M。任何一个线程T都能多次锁定O对应的监听器M,每一次解锁M的操作的影响刚好与每一次锁定M的操作的影响相反。

同步块也被称之为同步语句,程序实现的方式是synchronized(expression){code},其中expression返回的是Java类或者Java类的实例对象O,则同步块使用O的监听器作为同步锁。同步方法的程序实现方式是使用synchronized关键字修饰Java类的方法m,如果m是静态方法,则使用Java类的监听器作为同步锁,如果m是非静态方法,则使用Java类的实例对象的监听器作为同步锁。

Java程序语言不提供在多线程运行环境中对死锁的检测机制,用户需要在程序设计的过程中使用常用的技术手段避免死锁的发生,例如常用的技术手段包括设置锁的优先级、使用不同的锁粒度、设定更加公平的资源争夺机制。

除了以上的同步机制,Java程序语言还提供volatile关键字修饰变量直接读写主内存区域中的对象或者值、提供java.util.concurrent工具包支持更细粒度的并发编程模型。

3 Wait Sets and Notification

Wait Sets and Notification中文表示的是等待集合与通知,每一个Java对象都关联一个监听器(monitor)以及关联一个等待集合,其中监听器用于同步锁、等待集合用于存储阻塞等待中的线程列表。

当一个Java对象刚被创建的时候,与其关联的等待集合是空的,对等待集合的基本操作如增加线程到集合或者从集合中删除线程是原子操作。等待集合只可以使用Object.wait,、Object.notify、Object.notifyAll三个方法实行操作。

对等待集合的操作可以被一个线程的中断(interruption)状态、Thread类相关的中断(Thread.interrupt)方法影响。此外,Thread类的睡眠(Thread.sleep)方法以及连接(Thread.join)其他线程方法是从以上等待(Object.wait)方法或者通知(Object.notify、Object.notifyAll)方法中获取属性。也就是,当一个Java类或者类对象实例O同时被多个并发线程调用的时候,对象实例O与等待集合中的线程之间使用各种信号或者状态实行交互与协作。

3.1 Wait

Wait中文表示的是等待,在线程中表示一种等待状态或者等待操作,触发等待操作可以调用Object.wait方法、Object.wait(long millisecs)方法、Object.wait(long millisecs, int nanosecs)方法,当wait方法的参数等于0,以上三个方法的实现功能一样。

当调用以上的wait方法时,如果没有发生InterruptedException异常,则表示对应的当前线程能正常返回。

假设一个当前线程t调用一个对象m的等待方法wait,其中t将对m执行n个锁操作(表示t即将持有m的监听器的n次锁),则即将发生的行为:

  • 当n=0(t没有持有m的监听器的锁,即当前线程t不是对象m的监听器的线程拥有者)的时候,发生IllegalMonitorStateException异常

  • 如果wait方法中带有时间参数P,如果P不在0-999999值的范围内或者P是负数,则发生IllegalArgumentException异常

  • 当t被中断,则发生InterruptedException异常,同时t的中断状态设置为false

当以上的异常状态没有发生,则按照以下步骤执行:

1

t被增加到m的等待集合T中,同时执行对m的监听器的n次解锁操作,此时,t让出资源m给其他线程

2

t不再执行任何指令,直到t从等待集合T中被删除,t被删除的原因包括以下的场景(t将恢复之前的状态继续执行资源m):

  • m的notify方法被执行,m的等待集合T中的线程t被选中,并且t从T中被删除

  • m的notifyAll方法被执行

  • t的interrupt方法被执行

  • 如果是m处于等待状态中,则等待时间结束时,t从T中被删除

每一个线程t都必须确定收到的多个事件的执行顺序,这些事件能触发t从等待集合T中被删除,例如,假如t是在m的T中,t的intterupt事件e1与m的notify事件e2同时到达,则t必须确定e1与e2事件的执行顺序,如果先执行e1,则t将从m的wait等待状态中恢复并且抛出InterruptedException异常,T中的某个其他线程将收到通知。如果先执行e2,t将从m的wait等待状态中正常恢复。无论e1或者e2谁先被执行,最终e1与e2都必须被执行,但是执行的顺序必须由t确定。                                                                 

3

t对m执行n次锁操作

4

t从m的等待集合T被删除(执行第二步骤,原因是interrupt),t的中断状态设置为false,同时wait方法抛出InterruptedException异常。

3.2 Notification

Notification中文表示的是通知,用于多线程运行环境中线程之间的消息交互与协作,触发通知的方式是调用方法Object.notify、Object.notifyAll。

假设一个当前线程t调用一个对象m的通知方法(notify、notifyAll),其中t将对m执行n次锁操作(表示t即将持有m的监听器的n次锁),则即将发生的行为:

  • 当n=0(t没有持有m的监听器的锁,即当前线程t不是对象m的监听器的线程拥有者)的时候,发生IllegalMonitorStateException异常

  • 如果n大于0,调用通知方法(notify)时m的等待集合T非空,则从T中选择一个线程u并且u从T中被删除,当从T中选择线程时并不能保证指定选择那个线程,选择算法是由系统确定的,当u已经从T中删除,t对m实行n次解锁操作,此时,u从等待状态中恢复继续执行m的资源。

  • 如果n大于0,调用通知方法(notifyAll)时m的等待集合T非空,则T中的所有线程被删除,并且全部被删除的线程从等待状态中恢复,这些已经恢复的线程将继续争夺对m的监听器的锁定操作。

3.3 Interruptions

Interruption中文的意思是中断,用于设置线程的中断状态,其调用方式是单一线程的调用Thread.interrupt、线程组的调用ThreadGroup.interrupt。

假设当前线程t调用其他线程u的interrupt方法,在某些场景下u与t是相同的线程,此时,u的中断状态设置为true。另外,如果存在对象m的等待集合T中包含u,则u将从T中被删除,然后u从等待状态恢复,如果u再次尝试获取m的监听器的锁的时候,则抛出InterruptedException异常。

调用Thread.isInterrupted方法可以获取到当前线程的中断状态,调用Thread.interrupted方法可以获取当前线程的中断状态或者清除当前线程的中断状态。

3.4 Interactions of Waits, Notification, and Interruption

如前面所述,线程使用同步、等待、通知以及中断等机制实现线程之间的协作与交互。假如一个处于等待中的线程同时收到通知与中断的信号,其可能发生的行为如下所述:

  • 从wait方法中正常返回,同时也会执行中断的操作,也就是当调用Thread.interrupted方法时返回当前线程的中断状态是true

  • 从wait方法中异常返回,抛出的异常是InterruptedException

在以上的场景当前线程可以不重置其中断状态,并且从wait方法中正常返回。

同理,通知信息不能从中断中丢失。假设对象m的等待集合T,线程u执行m的notify通知操作,则可能发生的行为如下所述:

  • 至少有一个线程从T从被删除,从wait方法中正常返回

  • T中的所有线程都被删除,T中的所有线程都从wait方法中异常返回,抛出InterruptedException

综上所述,假如一个线程同时被通知与中断,则该线程最终会从wait方法中返回,并且抛出异常InterruptedException,然后,需要向T中的某个其他线程发送通知信息。

(未完待续)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wangys2006

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值