Synchronized和Lock接口

这篇具有很好参考价值的文章主要介绍了Synchronized和Lock接口。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Synchronized

Synchronized关键字回顾

synchronized是java中的关键字,是一种同步锁。它修饰的目标有以下几种:

  • 1.修饰一个代码块,被修饰的代码块称为同步代码块,其作用的范围是大括号{},括起来的代码,作用的对象是调用这个代码块的对象,synchronized不能修饰静态代码块。
  • 2.修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是所有调用这个方法的对象。
  • 3.修饰一个静态方法,其作用范围是整个静态方法,作用的对象是这个类的所有对象。
  • 4.修饰一个类对象(类的class对象),其作用范围是synchronized后面括号括起来的部分,作用对象是这个类的所有对象。

作用的对象,有点不了解。以及synchronized锁作用在this对象,和作用在类.class上有什么区别?学完后面的课程,记得来回答这个问题。

关于synchronized的理解,共有两种类型的锁:

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

synchronized锁的访问规则

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

判断是否同一把synchronized锁

(1)不同类型的锁不是同一把锁。
(2)加的是对象锁,那么必须是同一个对象实例才是同一把锁。
(3)加的是类锁,那必须是同一类才是同一把锁。

对于synchronized修饰的代码能否访问

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

注意事项

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

多线程编程步骤(上)

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

售票案例

sale 销售 ticket 票
案例要求,3个售票员进行售票,共售卖30张票。

代码
/**
 * @author 长名06
 * @version 1.0
 * 多线程编程步骤,第一步 创建资源类,定义属性和方法
 * 第二步,创建多个线程,调用资源类的操作方法
 */
public class SaleTickets {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(() -> {
            for (int i = 0; i < 40; i++){
                ticket.sale();
            }
        }, "aa").start();

        new Thread(() -> {
            for (int i = 0; i < 40; i++){
                ticket.sale();
            }
        }, "bb").start();

        new Thread(() -> {
            for (int i = 0; i < 40; i++){
                ticket.sale();
            }
        }, "cc").start();

    }
}

class Ticket {
    //票数
    private static int number = 30;

    public synchronized void sale() {
        if (number > 0) {
            System.out.println(Thread.currentThread().getName() + "\t 卖出一张票"
                    + "剩下票数为" + --number);
        }
    }
}
代码分析
  • 1.synchronized关键字修饰的非静态方法,此时这个方法的锁就是synchronized(this)锁,就是对调用当前方法的对象上锁。案例中的aa,bb,cc线程都是使用ticket这同一个对象,调用的sale()方法,所以这三个线程是互斥的,同时只能由三个中的一个,使用sale()方法。从输出结果,也可以看出,是互斥访问的。

  • 2.当一个线程获取了对应的锁,可以访问对应锁的代码块,其他需要访问该代码块的线程,就要等待。等待获取锁的线程释放锁,但是获取到锁的线程的执行有两种情况。
    1)获取锁的线程,执行对应的代码块,然后线程释放锁,无事发生,正常情况;
    2)拥有锁的线程执行中,出现了异常,此时JVM会让线程自动释放锁。

  • 3.但如果获取锁的线程的操作,需要等待IO或者其他原因(如sleep方法)被阻塞了,但是线程没有释放锁,其他的线程就只能等待,会很影响执行效率。所以需要一种机制可以不让等待的线程一直无限的等待下去(等待一定的时间,就能响应中断),通过Lock(java.util.concurrent.locks包下的接口)就可以实现。

  • 4.以上锁都是synchronized锁。

Lock

基本介绍

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

Lock和synchronized的区别
  • 1.Lock不是java语言内置的关键字,synchronized是Java语言的关键字,是内置特性。Lock是一个接口,可以通过其实现类实现异步访问。
  • 2.采用synchronized关键字,不需要用户去手动释放锁,当synchronized关键字修饰的方法或代码块执行完之后,有JVM自动让线程释放锁。但是Lock则必须让用户手动释放锁,如果没有主动释放锁,就可能会出现死锁现象。
使用Lock实现sale_ticket案例
import java.util.concurrent.locks.ReentrantLock;
/**
 * @author 长名06
 * @version 1.0
 * 多线程编程步骤,第一步 创建资源类,定义属性和方法
 * 第二步,创建多个线程,调用资源类的操作方法
 */
public class SaleTickets {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        new Thread(() -> {
            for (int i = 0; i < 40; i++){
                ticket.sale();
            }
        }, "aa").start();

        new Thread(() -> {
            for (int i = 0; i < 40; i++){
                ticket.sale();
            }
        }, "bb").start();

        new Thread(() -> {
            for (int i = 0; i < 40; i++){
                ticket.sale();
            }
        }, "cc").start();

    }
}

class Ticket {
    //票数
    private static int number = 30;

    private final ReentrantLock lock = new ReentrantLock();

    public void sale() {
        lock.lock();//开启锁
        try {
            if (number > 0) {
                System.out.println(Thread.currentThread().getName() + "\t 卖出一张票"
                        + "剩下票数为" + --number);
            }
        }finally {
            lock.unlock();//释放锁
        }

    }
}
关于Thread#start()&start0()
public synchronized void start() {//这个方法,完成线程的启动,但是实际创建线程是start0()方法完成的
    /**
     * This method is not invoked for the main method thread or "system"
     * group threads created/set up by the VM. Any new functionality added
     * to this method in the future may have to also be added to the VM.
     *
     * A zero status value corresponds to state "NEW".
     */
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    /* Notify the group that this thread is about to be started
     * so that it can be added to the group's list of threads
     * and the group's unstarted count can be decremented. */
    group.add(this);

    boolean started = false;
    try {
        start0();//这里这个方法的调用,才是完成线程的创建
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
            /* do nothing. If start0 threw a Throwable then
              it will be passed up the call stack */
        }
    }
}

private native void start0();//此方法,java代码无法完成,而是用native关键字修饰的方法,就是使用jvm底层的JNI(Java Native Interface)机制调用c语言库完成的。这个创建线程的方法,以及是否创建,创建顺序,不是由java程序决定的,而是由程序运行的OS决定的。
lock接口方法
public interface Lock {
	void lock();//获取锁
	void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
	void unlock();//释放锁
    Condition newCondition();
}
lock方法

lock()方法使用最多的方法,功能,获取锁,如果锁被其他线程获取,则进行等待。
使用Lock,必须主动去释放锁,并且发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}finally{}块中进行,并且将释放锁的操作在finally块中,用来保证锁一定被释放,防止死锁的发生。通常使用Lock实现同步的,是以如下形式的。

lock.lock();//开启锁
try {
    //...具体代码
}catch(Exception e){
    
}
finally {
    lock.unlock();//释放锁
}
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有以下几点不同

  • 1.Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现的。
  • 2.synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生。Lock在发生异常时,如果没有主动通过unLock()会释放锁,则很可能会造成死锁现象,因此使用Lock时需要在finally块中释放锁。
  • 3.Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一致等待,不能够使用中断。
  • 4.通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
  • 5.Lock可以提高多个线程进行读操作的效率。
    在性能上来说,如果资源竞争不激烈,二者的性能是差不多的,而当资源竞争激烈时,此时Lock的性能要远远优于synchronized。

只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。文章来源地址https://www.toymoban.com/news/detail-711183.html

到了这里,关于Synchronized和Lock接口的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【JavaEE】Java中复杂的Synchronized关键字

    目录  一、synchronized的特性 (1)互斥 (2)刷新内存 (3)可重入 二、synchronized的使用 (1)修饰普通方法 (2)修饰静态方法 (3)修饰代码块 三、synchronized的锁机制 (1)基本特点 (2)加锁工作过程 1.偏向锁 2.轻量级锁 3.重量级锁 (3)优化操作 1.锁消除 2.锁粗化 四、

    2024年01月19日
    浏览(35)
  • Java 八股文面试过程系列之synchronized关键字

    本文通过一场虚拟的面试对话,详细解析了Java中的synchronized关键字。从基本用法到底层实现原理,再到性能优化策略,全面提升您对同步机制的理解。

    2024年02月07日
    浏览(39)
  • Java关键字之synchronized详解【Java多线程必备】

    点击   Mr.绵羊的知识星球  解锁更多优质文章。 目录 一、介绍 二、特性 1. 线程安全 2. 互斥访问 3. 可重入性 4. 内置锁 三、实现原理 四、和其他锁比较 1. 优点 2. 缺点 五、注意事项和最佳实践 六、使用案例 1. 案例一 2. 案例二     synchronized是Java中最基本的同步机制之一,

    2024年01月24日
    浏览(38)
  • 线程的状态,多线程带来的风险,synchronized关键字及死锁问题

    目录 状态  线程的意义 多线程带来的风险——线程安全✅ 线程安全的概念 线程不安全的原因 抢占式执行,随机性调度 修改共享数据 原子性-加🔒 可见性 指令重排序 解决线程不安全问题(学完线程再总结) synchronized——监视器锁monitor lock​编辑   互斥 使用示例

    2024年02月06日
    浏览(40)
  • 《吊打面试官系列》从源码全面解析 synchronized 关键字的来龙去脉

    👏作者简介:大家好,我是爱敲代码的小黄,独角兽企业的Java开发工程师,CSDN博客专家,阿里云专家博主 📕系列专栏:Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙、Spring从成神到升仙系列 🔥如果感觉博主的文章还不错的话,请👍三连支持👍一

    2023年04月16日
    浏览(37)
  • Alibaba(按关键字搜索商品) API接口

    为了进行电商平台 的API开发,首先我们需要做下面几件事情。 1)开发者注册一个账号 2)然后为每个alibaba应用注册一个应用程序键(App Key) 。 3)下载alibaba API的SDK并掌握基本的API基础知识和调用 4)利用SDK接口和对象,传入AppKey或者必要的时候获取并传入SessionKey来进行程序

    2024年02月09日
    浏览(37)
  • taobao平台上关键字的API接口接入说明

        淘宝API接口是一个丰富的接口库,提供了各种各样的接口供开发者使用。满足多语言开发。以下是一些常见的淘宝API接口及其代码示例。 1. 搜索商品API接口 该API提供了搜索淘宝商品的功能,可以使用各种编程语言来访问。以下代码段展示了使用Python来调用该API的

    2024年02月08日
    浏览(29)
  • 义乌购关键字搜索API接口技术详解与代码示例

    义乌购搜索API接口技术详解与代码示例 在电子商务蓬勃发展的今天,义乌购作为国内知名的批发市场平台,为广大商家和消费者提供了丰富的商品资源。为了方便开发者快速接入义乌购平台,实现商品信息的搜索与获取,义乌购开放了搜索API接口。本文将详细介

    2024年03月17日
    浏览(46)
  • 苏宁API接口解析,实现按关键字搜索suning商品

    苏宁API接口提供了多种搜索商品的方式,其中包括按搜索。下面是一个简单的示例,演示如何使用苏宁API接口实现按搜索商品: 请求参数 请求参数:q=鞋子start_price=end_price=page=cat=discount_only=sort=page_size=seller_info=nick=ppath= 参数说明:q:搜索 cat:分类ID start_p

    2024年02月09日
    浏览(40)
  • Java | interface 和 implements关键字【接口,看这篇就够了】

    学完 继承 、学完 多态 ,但面对汹涌而来🌊的接口,相信很多同学都不知所措,因此我耗费几天几夜的时间,搜寻大量书籍资料,苦心闭关钻研,写出了一篇关于Java的接口从 入门小白到精通大佬 的学习之路,相信这篇文章一定对您有所帮助📖 Java接口是一系列方法的声明

    2024年02月19日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包