前言:
Lock 替代了 synchronized
Condition 替代了 Object中的wait 和notify 方法
为什么Lock会替代synchroized?
synchronized的局限性
- 占有锁的线程等待IO或者其他原因被阻塞,没有释放锁的情况下,其他线程一直阻塞
- 多个线程同时读写文件的时候,读和读操作也会发生冲突
- 我们没有办法知道当前我们的线程是否成功获取了锁,只能傻傻的等待
引用API的一段是:
-
Condition
factors out theObject
monitor methods (wait
,notify
andnotifyAll
) into distinct objects to give the effect of having multiple wait-sets per object, by combining them with the use of arbitraryLock
implementations. Where aLock
replaces the use ofsynchronized
methods and statements, aCondition
replaces the use of the Object monitor methods.
用法是:
Lock lock = new ReentrantLock();
Condition notFull = lock.newCondition();
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signalALl();
} finally {
lock.unlock();
}
}
lock8锁
一、题目
1、标准访问,先发送邮件还是短信 Email 锁是this 2、暂停4S在邮件方法里,先发送邮件还是短信 Email 锁是this 3、新增hello普通方法,先发送邮件还是hello hello 加个普通方法后发现和同步锁无关 4、有两部手机,先发送邮件还是短信 EMS 锁是两个不同的this,但是需要隔4s才能发送email 5、两个静态同步方法,有一部手机,先发送邮件还是短信 Email 锁的是同一个Class对象 6、两个静态同步方法,有2部手机,先发送邮件还是短信 Email 锁的是同一个Class对象 7、一个普通同步方法,一个静态同步方法,一部手机,先发送邮件还是短信 EMS 两个锁,一个是this,一个是Class,但是需要隔4s才能发送email 8、一个普通同步方法,一个静态同步方法,2部手机,先发送邮件还是短信 EMS 两个锁,一个是this,一个是Class,但是需要隔4s才能发送email
二、笔记
笔记:
一个对象里面如果有多个synchronized方法,某个时刻内,只要一个线程去调用其中一个synchronized方法了,其他的线程都要等待
换句话说,在某个时刻内,只能有唯一一个线程去访问这些synchronized方法,
锁的是当前对象this,被锁定后,其他的线程都不能进入到当前对象的其他的synchronized方法
加个普通方法后发现和同步锁无关
换成两个对象后,不是同一把锁,情况立刻变化
都换成静态同步方法后,情况又变化了
所有的非静态的同步方法用的都是同一把锁----实例对象本身
synchronized实现同步的基础:java中的每一个对象都可以作为锁
具体的表现为以下三种形式:
对于普通同步方法,锁的是当前实例对象
对于静态同步方法,锁的是当前的Class对象。
对于同步方法块,锁是synchronized括号里面的配置对象
当一个线程试图访问同步代码块时,他首先必须得到锁,退出或者是抛出异常时必须释放锁
也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,
可以是别的实例对象非非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,
所以必须等待该实例对象已经获取锁的非静态同步方法释放锁就可以获取他们自己的锁。
所有的静态同步方法用的也是同一把锁----类对象本身
这两把锁的是两个不同的对象,所以静态的同步方法与非静态的同步方法之间是不会有竞争条件的
但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,
而不是同一个实例对象的静态同步方法之间,
还是不同的实例对象的静态同步方法之间,只要他们用一个的是同一个类的实例对象。
三、举例
1、资源类
class Phone{
public synchronized void senEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(4);
System.out.println("------sendEmail");
}
public synchronized void senSMS(){
System.out.println("-------denSMS");
}
public void hello(){
System.out.println("-----hello");
}
}
2、测试类
public class Lock8 {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
new Thread(() -> {
try {
phone.senEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
Thread.sleep(100); //为的是先A线程访问
new Thread(() -> {
try {
// phone.senSMS();
phone.hello();
} catch (Exception e) {
e.printStackTrace();
}
},"B").start();
}
}