ToB企服应用市场:ToB评测及商务社交产业平台

标题: Synchronized和Lock接口 [打印本页]

作者: 数据人与超自然意识    时间: 2023-11-17 07:24
标题: Synchronized和Lock接口
Synchronized

Synchronized关键字回顾

synchronized是java中的关键字,是一种同步锁。它修饰的对象有以下几种:
作用的对象,有点不了解。以及synchronized锁作用在this对象,和作用在类.class上有什么区别?学完后面的课程,记得来回答这个问题。
关于synchronized的理解,共有两种类型的锁:

(1)类锁:只有synchronized修饰静态方法或者修饰一个类的class对象时,才是类锁。
(2)对象锁:除了类锁,所有其他的上锁方式都认为是对象锁。比如synchronized修饰普通方法或者synchronized(this)给代码块上锁等。
应该注意的是,因为一个类只有一个class对象,因此所有的访问者在访问被加了类锁的代码时,都是共用同一把锁,而类的实例却可以有很多个,因此不同对象访问加了对象锁的代码,它们的访问互不干扰。
synchronized锁的访问规则

(1)加了相同锁的代码,它们的访问规则是相同的,即当某个访问者获得该锁时,它们一起向该访问者开放访问,向其他没有获得该锁的访问者关闭访问。
(2)加了不同锁的代码访问互相不干扰。
(3)而没有加锁的代码随时都可以任意访问,不受任何限制。
判断是否同一把synchronized锁

(1)不同类型的锁不是同一把锁。
(2)加的是对象锁,那么必须是同一个对象实例才是同一把锁。
(3)加的是类锁,那必须是同一类才是同一把锁。
对于sysnchronized修饰的代码能否访问

1.首先判断是不是同一把锁。
2.然后判断各自的访问规则。
注意事项

虽然synchronized关键字可以来修饰方法,但synchronized关键字不属于方法定义的一部分。因此,synchronized关键字不能被继承。如果在父类中的某个方法使用了synchronized关键字,子类又覆盖了该方法,在子类中的方法默认情况下是不进行同步的,而必须显示在子类的方法上也加上synchronized关键字才可以。当然,也可以在子类中直接调用父类方法,这样虽然子类方法不同步但是方法体的内容,是同步的,因此相当于子类方法也同步。
多线程编程步骤(上)

第一,创建资源类,创建属性和操作方法。第二 创建多线程调用资源类的方法。
售票案例

sale 销售 ticket 票
案例要求,3个售票员进行售票,共售卖30张票。
代码
  1. /**
  2. * @author 长名06
  3. * @version 1.0
  4. * 多线程编程步骤,第一步 创建资源类,定义属性和方法
  5. * 第二步,创建多个线程,调用资源类的操作方法
  6. */
  7. public class SaleTickets {
  8.     public static void main(String[] args) {
  9.         Ticket ticket = new Ticket();
  10.         new Thread(() -> {
  11.             for (int i = 0; i < 40; i++){
  12.                 ticket.sale();
  13.             }
  14.         }, "aa").start();
  15.         new Thread(() -> {
  16.             for (int i = 0; i < 40; i++){
  17.                 ticket.sale();
  18.             }
  19.         }, "bb").start();
  20.         new Thread(() -> {
  21.             for (int i = 0; i < 40; i++){
  22.                 ticket.sale();
  23.             }
  24.         }, "cc").start();
  25.     }
  26. }
  27. class Ticket {
  28.     //票数
  29.     private static int number = 30;
  30.     public synchronized void sale() {
  31.         if (number > 0) {
  32.             System.out.println(Thread.currentThread().getName() + "\t 卖出一张票"
  33.                     + "剩下票数为" + --number);
  34.         }
  35.     }
  36. }
复制代码
代码分析

Lock

基本介绍

Lock锁实现,并提供了比使用同步方法和语句可以获得的更广泛的锁操作。它们允许更灵活的结构,可能具有非常不同的属性,并且可能支持多个关联的条件对象。Lock提供了比synchronized更多的功能。
Lock和synchronized的区别

使用Lock实现sale_ticket案例
  1. import java.util.concurrent.locks.ReentrantLock;
  2. /**
  3. * @author 长名06
  4. * @version 1.0
  5. * 多线程编程步骤,第一步 创建资源类,定义属性和方法
  6. * 第二步,创建多个线程,调用资源类的操作方法
  7. */
  8. public class SaleTickets {
  9.     public static void main(String[] args) {
  10.         Ticket ticket = new Ticket();
  11.         new Thread(() -> {
  12.             for (int i = 0; i < 40; i++){
  13.                 ticket.sale();
  14.             }
  15.         }, "aa").start();
  16.         new Thread(() -> {
  17.             for (int i = 0; i < 40; i++){
  18.                 ticket.sale();
  19.             }
  20.         }, "bb").start();
  21.         new Thread(() -> {
  22.             for (int i = 0; i < 40; i++){
  23.                 ticket.sale();
  24.             }
  25.         }, "cc").start();
  26.     }
  27. }
  28. class Ticket {
  29.     //票数
  30.     private static int number = 30;
  31.     private final ReentrantLock lock = new ReentrantLock();
  32.     public void sale() {
  33.         lock.lock();//开启锁
  34.         try {
  35.             if (number > 0) {
  36.                 System.out.println(Thread.currentThread().getName() + "\t 卖出一张票"
  37.                         + "剩下票数为" + --number);
  38.             }
  39.         }finally {
  40.             lock.unlock();//释放锁
  41.         }
  42.     }
  43. }
复制代码
关于Thread#start()&start0()
  1. public synchronized void start() {//这个方法,完成线程的启动,但是实际创建线程是start0()方法完成的
  2.     /**
  3.      * This method is not invoked for the main method thread or "system"
  4.      * group threads created/set up by the VM. Any new functionality added
  5.      * to this method in the future may have to also be added to the VM.
  6.      *
  7.      * A zero status value corresponds to state "NEW".
  8.      */
  9.     if (threadStatus != 0)
  10.         throw new IllegalThreadStateException();
  11.     /* Notify the group that this thread is about to be started
  12.      * so that it can be added to the group's list of threads
  13.      * and the group's unstarted count can be decremented. */
  14.     group.add(this);
  15.     boolean started = false;
  16.     try {
  17.         start0();//这里这个方法的调用,才是完成线程的创建
  18.         started = true;
  19.     } finally {
  20.         try {
  21.             if (!started) {
  22.                 group.threadStartFailed(this);
  23.             }
  24.         } catch (Throwable ignore) {
  25.             /* do nothing. If start0 threw a Throwable then
  26.               it will be passed up the call stack */
  27.         }
  28.     }
  29. }
  30. private native void start0();//此方法,java代码无法完成,而是用native关键字修饰的方法,就是使用jvm底层的JNI(Java Native Interface)机制调用c语言库完成的。这个创建线程的方法,以及是否创建,创建顺序,不是由java程序决定的,而是由程序运行的OS决定的。
复制代码
lock接口方法
  1. public interface Lock {
  2.         void lock();//获取锁
  3.         void lockInterruptibly() throws InterruptedException;
  4.     boolean tryLock();
  5.     boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
  6.         void unlock();//释放锁
  7.     Condition newCondition();
  8. }
复制代码
lock方法

lock()方法使用最多的方法,功能,获取锁,如果锁被其他线程获取,则进行等待。
使用Lock,必须主动去释放锁,并且发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}finally{}块中进行,并且将释放锁的操作在finally块中,用来保证锁一定被释放,防止死锁的发生。通常使用Lock实现同步的,是以如下形式的。
  1. lock.lock();//开启锁
  2. try {
  3.     //...具体代码
  4. }catch(Exception e){
  5.    
  6. }
  7. finally {
  8.     lock.unlock();//释放锁
  9. }
复制代码
newCondition方法

关键字synchronizedwait()/notify()这两个方法一起使用,可实现等待/通知模式。Lock锁的newCondition()方法返回Condition对象,Condition类也可以实现等待/通知的模式。wait()和notify()是Object类下的方法,notify()被调用时,JVM会随机的唤醒某个等待的线程,使用Condition类可进行选择性通知,Condition常用的方法,awiat()方法,会使当前线程等待,同时会释放当前线程持有的锁,当其他线程调用signal()时,线程会重新获得锁并继续执行。signal()用于唤醒等待的线程。
注意,在使用Condition接口(使用其具体的实现类)的await()和signa()方法前,需要线程持有相关的Lock锁,调用await()后线程会释放这个锁,在signal()调用后会从当前Condition对象的等待队列中,唤醒一个线程,唤醒的线程尝试获得锁,一旦获得锁成功,就执行。
小结

Lock和synchronized有以下几点不同
只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4