概况
本文主要介绍Java中同步的概念、类型、使用等相关内容。
相关概念
Java同步
- Java同步是控制多线程访问任意共享资源的能力
- 在想要允许唯一一个线程访问共享资源时Java同步是一种更好的选择
为什么使用同步
- 阻止线程干涉
- 阻止一致性问题
同步类型
- 进程同步
- 线程同步
线程同步
- 互斥锁
- 协作(Java线程间通信)
Java锁的概念
- 同步是由称为锁或监视器的内部实体构建
- 每个对象有一个与之关联的锁
- 按照惯例,一个需要持续访问一个对象的域的线程不得不在访问之前获取对象的锁,当完成访问后释放该锁
互斥锁
互斥锁帮助在共享数据时阻止线程相互干涉
Java同步方法
- 同步方法因任意共享资源用于锁定一个对象
- 当一个线程调用同步方法时,自动获取对象的锁,并且当线程完成任务时释放该锁
Java同步块
- 同步块因任意共享资源用于锁定一个对象
- 同步块的作用范围比同步方法更小
Java静态同步
- 如果让任意的静态方法同步,这个锁会在类上而不是对象上
- 也可以在同步块上使用类锁
Java死锁
- Java死锁是多线程的一部分
- 死锁发生情况:一个对象等待被另一个线程获取的对象锁,并且另一个线程也在等待被第一个线程获取的对象锁。因为两个线程都在等待对方释放对象锁,这种情况称为死锁
Java线程间通信
- 线程间通信或协作是关于允许同步线程相互通信
- 协作(线程间通信)是一种机制,即在关键部分运行着的线程被暂停,同时另一个线程在同一关键部分被允许进入或锁住
wait()
- 引起当前线程释放锁,直到另一个线程要么调用
notify()
或notifyAll()
方法或指定的时间已经过去 - 当前线程必须拥有对象的监视器,所以
wait()
方法必须从同步方法内被调用,否则会抛出异常 - public final void wait() throws InterruptedException: 等待直到对象被通知
- public final void wait(long timeout) throws InterruptedException: 等待指定的时间
notify()
- 唤醒正在等待这个对象的监视器的一个单独线程
- 如果一些线程正在这个对象上等待,其中一个线程被选择唤醒
- 这种选择是随意的,并且由执行自行决定
notifyAll()
- 唤醒等待这个对象的监视器的所有线程
理解线程间通信的过程
- 线程开始获取锁
- 锁被线程获取
- 如果调用
wait()
方法,线程进入暂停状态,否则线程释放锁并退出 - 如果调用
notify()
或notifyAll()
方法,线程进入被通知状态(可运行状态) - 线程可获取锁
- 任务完成后,线程释放锁,并退出对象的监视状态
特点
wait()
,notifiy()
和notifyAll()
方法与锁关联,并且对象有锁,所以这些方法被定义在Object
类而不是Thread
类
wait()和sleep()方法的区别
wait() | sleep() |
---|---|
wait() method releases the lock | sleep() method doesn’t release the lock. |
is the method of Object class | is the method of Thread class |
is the non-static method | is the static method |
is the non-static method | is the static method |
should be notified by notify() or notifyAll() methods | after the specified amount of time, sleep is completed. |
中断线程
- 如果一个线程正在休眠或等待状态(sleep()或wait()方法被调用),在这个线程上调用
interrupt()
方法,会打破休眠或等待状态,抛出异常 - 如果一个线程不在休眠或等待状态,调用
interrupt()
方法表现正常的行为,不中断线程,但是设置中断标记为true
- public void interrupt()
- public static boolean interrupted()
- public boolean isInterrupted(): 返回中断的标记(
true
或false
)
重进入监视器
- 如果一个方法可以从方法内部调用,Java线程因不同的同步方法可重用同一监视器
- 终结了单线程死锁的可能性