释放锁时的不同情况:
情况:
1.当前线程的同步方法,同步代码块执行结束。
eg:上厕所,完事处理。
- 当前线程在同步代码块,同步方法中遇到break,return。
eg:没有正常的完事,经理叫他修改bug,不得已出来
- 当前线程在同步代码块,同步方法中出现了未处理的Error或Exception,导致异常结束
eg:没有正常的完事,发现忘带纸,不得已出来
- 当前线程在同步代码块,同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。
eg:没有正常完事,需要酝酿一下,所以出来等会再进去。
不会释放锁情况:
- 线程执行同步代码块或同步方法时,程序调用Thread.sleep(),Thread.yield()方法暂停当前线程的执行,不会释放锁。
eg:上厕所,太困了,在坑位上眯了一会。
- 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁。
注意:尽量避免使用suspend()和resume()来控制线程,方法不再推荐使用。
wait/notify 机制
Java线程通信之wait/notify机制 - 知乎 (zhihu.com)
一个线程调用Object的wait()方法,使其线程被阻塞;
另一线程调用Object的notify()/notifyAll()方法,wiat()阻塞的线程继续执行。
实现条件:
调用wait线程和notify线程必须拥有相同对象锁。
wait()方法和notify()/notifyAll()方法必须在Synchronized方法或代码块中。
wait方法
在执行wait()方法前,当前线程必须已获得对象锁。调用它时会阻塞当前线程,进入等待状态,在当前wait()处暂停线程。
wait()方法执行后,会立即释放获得的对象锁。
notify 方法
在执行notify方法前,当前线程也必须已获得线程锁。
调用notify()方法后,会通知一个执行了wait()方法的阻塞等待线程,使该等待线程重新获得取到对象锁,然后继续执行wait()后面的代码。
与wait()方法不同,执行notify()后,不会立即释放对象锁,而需要执行完synchronized的代码块或方法才会释放锁,所以接收通知的线程也不会立即获得锁,也需要等待执行notify()方法的线程释放锁后再获取锁。
notifyAll()
通知所有等待状态的线程,用notifyAll唤醒所有线程。
公平锁与非公平锁
公平锁:
多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。
- 优点:所有的线程都能得到资源,不会饿死在队列中。
- 缺点:吞吐量会下降很多,队列里面除了第一个线程,其他的线程都会阻塞,cpu唤醒阻塞线程的开销会很大。
非公平锁:
多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。
- 优点:可以减少CPU唤醒线程的开销,整体的吞吐效率会高点,CPU也不必取唤醒所有线程,会减少唤起线程的数量。
- 缺点:你们可能也发现了,这样可能导致队列中间的线程一直获取不到锁或者长时间获取不到锁,导致饿死。
递归锁(可重入锁)
原理:任何线程获取了锁之后可以再次获取该锁而不会被阻塞,识别获取锁的线程是否为当前占据锁的线程,如果是则再次成功获取。获取锁后进行自增,
优点: 可以避免死锁。
共享锁
多个线程可以获取读锁,以共享的形式持有,本质上与乐观锁,读写锁一样,JAVA的共享锁也是ReentrantReadWriteLock
独占锁
只有一个线程可以获取锁,与悲观锁,互斥锁一样,JAVA的独占锁有:synchronized,ReentrantLock
实现:synchronized、ReentrantLock。
读写锁
读写锁是一种技术: 通过ReentrantReadWriteLock类来实现。为了提高性能, Java 提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,如果没有写锁的情况下,读是无阻塞的,在一定程度上提高了程序的执行效率。读写锁分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由 jvm 自己控制的。
读锁: 允许多个线程获取读锁,同时访问同一个资源。
写锁: 只允许一个线程获取写锁,不允许同时访问同一个资源。
如何使用
//创建一个读写锁
//它是一个读写融为一体的锁,在使用的时候,需要转换
private ReetrantReadWriteLock rwLock = new ReentrantReadWriteLock();
获取读锁和释放读锁
//获取读锁
rwLock.readLock().lock();
//释放读锁
rwLock.readLock().unlock();
获取写锁和释放写锁
//创建一个写锁
rwLock.writeLock().lock();
//写锁释放
rwLock.writeLock().unlock();
Lock锁
static Lock lock=new ReetrantLock();
public static void addNumber(){ lock.lock();//加锁
try{
number++;
}finally{
lock.unlock();//释放锁
}
}