锁Lock
1、常用函数总结
synchronized
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:
1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{
}括起来的代码,作用的对象是调用这个代码块的对象;
2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象
wait() 方法导致当前线程无限期地等待,直到另一个线程调用此对象的 notify() 或 notifyAll() 方法
wait(long timeout) 方法
使用此方法,我们可以指定一个超时,在此之后将自动唤醒线程。
当然了,我们可以在到达超时之前使用 notify() 或 notifyAll() 提前唤醒线程。
请注意,调用 wait(0) 与调用 wait() 相同
notify() 和 notifyAll() 方法用于唤醒等待访问此对象监视器的线程。
它们以不同的方式通知等待线程。
notify() 方法
对于在此对象的监视器上等待的所有线程(通过使用任何一个重载 wait() 方法),notify() 通知将会随机唤醒任何一个线程。
也就是说,我们并不能确切知道唤醒了哪个线程,这取决于实现。
因为 notify() 提供了唤醒一个随机线程的机制,因此它可用于实现线程执行类似任务的互斥锁定。
但在大多数情况下,使用 notifyAll() 会是一个更可行的方案。
notifyAll() 方法
notifyAll() 方法用于唤醒正在此对象的监视器上等待的所有线程。唤醒的线程将以常规的方式完成 - 就像任何其他线程一样。但,有一点要注意的是,对于任意一个线程,但在我们允许其继续执行之前,请始终快速检查继续执行该线程所需的条件。因为在某些情况下线程被唤醒而没有收到通知(这个场景将在后面的例子中讨论 )
Synchronized和Lock区别
- 1、Synchronized内置的Java关键字,Lock是一个Java类
- 2、Synchronized无法判断获取锁的状态,Lock 可以判断是否获取到了锁
- 3、Synchronized 会自动释放锁,lock必须要手动释放锁!如果不释放锁,死锁
- 4、Synchronized 线程1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下去;
- 5、Synchronized可重入锁,不可以中断的,非公平;Lock,可重入锁,可以判断锁,非公平(可以自己设置);
- 6、Synchronized适合锁少量的代码同步问题,Lock 适合锁大量的同步代码!
ReentrantLock锁
ReentrantLock是Java中常用的锁,属于乐观锁类型,多线程并发情况下。能保证共享数据安全性,线程间有序性
ReentrantLock通过原子操作和阻塞实现锁原理,一般使用lock获取锁,unlock释放锁。
Condition对象
使用Condition时,引用的Condition对象必须从Lock实例的newCondition()返回,这样才能获得一个绑定了Lock实例的Condition实例。
Condition提供的await()、signal()、signalAll()原理和synchronized锁对象的wait()、notify()、notifyAll()是一致的,并且其行为也是一样的:
await()会释放当前锁,进入等待状态;
signal()会唤醒某个等待线程;
signalAll()会唤醒所有等待线程;
唤醒线程从await()返回后需要重新获得锁。
此外,和tryLock()类似,await()可以在等待指定时间后,如果还没有被其他线程通过signal()或signalAll()唤醒,可以自己醒来。
2、测试
synchronized方法
package threadMain;
/** * @ProjectName: ES-Api * @Package: threadMain * @ClassName: syncThread * @Author: 125827 * @Description: 进程同步 * @Date: 1/10/2022 10:06 PM * @Version: 1.0 */
public class SyncThread {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for(int i = 0; i < 100; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(()->{
for(int i = 0; i < 100; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(()->{
for(int i = 0; i < 100; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
new Thread(()->{
for(int i = 0; i < 100; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "D").start();
}
}
/** 判断等待,业务,通知 */
class Data{
private int number = 0 ;
public synchronized void increment() throws InterruptedException {
while(number != 0 ){
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
//通知其他线程,这儿+1完毕
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
while(number ==0){
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
//通知其他线程,这儿+1完毕
this.notifyAll();
}
}
Lock方法
package threadMain;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/** * @ProjectName: ES-Api * @Package: threadMain * @ClassName: syncThread * @Author: 125827 * @Description: 进程同步 * @Date: 1/10/2022 10:06 PM * @Version: 1.0 */
public class lockThread {
public static void main(String[] args) {
Data2 data = new Data2();
new Thread(()->{
for(int i = 0; i < 20; i++) data.increment(); }, "A").start();
new Thread(()->{
for(int i = 0; i < 20; i++) data.decrement(); }, "B").start();
new Thread(()->{
for(int i = 0; i < 20; i++) data.increment(); }, "C").start();
new Thread(()->{
for(int i = 0; i < 20; i++) data.decrement(); }, "D").start();
}
}
/** 判断等待,业务,通知 */
class Data2{
/** 数字 资源*/
private int number = 0 ;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increment() {
lock.lock();
try {
while(number != 0 ){
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
//通知其他线程,这儿+1完毕
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public synchronized void decrement() {
lock.lock();
try {
while(number ==0){
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
//通知其他线程,这儿+1完毕
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
3、锁的静态方法问题
- 第一个问:
package lock8;
import java.util.concurrent.TimeUnit;
/** * @ProjectName: www-ES-Api * @Package: lock8 * @ClassName: Iphone * @Author: 125827 * @Description: 手机 * @Date: 1/11/2022 3:45 PM * @Version: 1.0 */
public class Phone {
/** synchronized锁的对象是方法的调用者! * 两个方法用的是同一个锁,谁先拿到谁执行! */
public synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendSms");
}
public synchronized void call(){
System.out.println("call");
}
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()-> {
phone.sendSms();},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call(); },"B").start();
}
}
// 输出:sendSms call
- 第二问:
package lock8;
import java.util.concurrent.TimeUnit;
/** * @ProjectName: ES-Api * @Package: lock8 * @Author: 125827 * @Date: 1/11/2022 3:45 PM * @Version: 1.0 */
public class PhoneHello {
/** * synchronized锁的对象是方法的调用者! * static静态方法 * 类一加载就有了! 锁的是cLass模板,创建两个对象,也是一个模板 */
public static synchronized void sendSms(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendSms");
}
public static synchronized void call(){
System.out.println("call");
}
}
文章评论