JAVA中的锁Synchronized和Lock区别

锁Lock

1、常用函数总结

synchronized
synchronizedJava中的关键字,是一种同步锁。它修饰的对象有以下几种: 
  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 适合锁大量的同步代码!
ReentrantLockReentrantLockJava中常用的锁,属于乐观锁类型,多线程并发情况下。能保证共享数据安全性,线程间有序性
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");
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45717907/article/details/122436062