zoukankan      html  css  js  c++  java
  • JAVA 多线程(1):synchronized

    入坑3年,对线程总是一知半解,最多停留在copy,决定还是仔细看看这方面的东西,一点点的记录让自己理解,对一些重要的概念进行记录和理解(包括参考作者的原话与个人理解)

    参考链接:https://www.cnblogs.com/wxd0108/p/5479442.html

    平行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。

    并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。

    这个图挺经典的:

    concurrent:并发

      一个咖啡厅,2队人排队,看谁跑的快,1队和2队是排好的,但是谁抢到就看2队人的身体素质了。(毫无人性可言)

    parallel:并行

      两个咖啡厅,大家都排队去买,很有顺序的说,至少不会发生打架或争吵。

    线程安全:指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果。

    一般情况下,如果不涉及事务处理的时候,比如批量导入某个数据表的数据时,如果其中不存在事务关系时,可以不用关心,比如100个人(100个线程)要进厕所等,厕所是公用的,那么大家都可以进去解决一下~  = =

    但是公共厕所不是免费的,那就要先买票再进去解决(这里比如厕所类有2个方法,一个是买票,一个是进厕所~ = =),大家都要先去买票,票的价格按顺序增加,第一个人是1块,第二人是2块,那么如果100个人都同时去买票,可能100个人会同时买到票(也有可能

    有前后),那么有可能大家都买到了1块钱的票,然后就都可以去上厕所了,但是买票的亏了啊,本来能赚5050 块钱,结果只收了100块钱~  (可能会有疑问的时候,现实生活中可能只有一个窗口,怎么会出现呢,这里希望不要去纠结这个事情,打个比方,如果也有100个卖票窗口,也希望能卖到5050 块钱的票,怎么办~  希望看这例子的人能看懂 - - 哈哈)

    所以,怎么办~?

    要求大家排队,强制要求不能同时买票,只设置一个窗口,或者即使2个窗口,也必须在A窗口卖完之后B窗口才能出票。这样保证100个人一定能卖出5050块钱的票。

    也就是要求同步操作,保证调用顺序。

    如果保证:加锁

    参考地址:https://www.cnblogs.com/wl0000-03/p/5973039.html

    synchronized:同步关键字

    相关锁知识

    java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。 java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,知道线程B释放这个锁,如果B线程不释放这个锁,那么A线程将永远等待下去。

    java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,但是,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的

    理解:

    锁是每个对象都有的,就好像每个房间都没有门一样(假设都有)。但是门上的锁需不需要用又是另一回事,有可能锁都是开开的。

    而如果一旦需要用钥匙打开门,那么每个房间就只能有一个人进入,这个人进去后,别人是进不来的,比如只有一个马桶的厕所,别人不能进来~ 只有等那人出来了,第二个人(线程)才能拿到钥匙开开门。

    对象锁和类锁:对象锁针对一个类可以有多个,因为对象实例可以有多个,但是的类只有一个class对象。

    所以,对象锁针对每个对象实例是互不干扰的,但是类锁会以为着会管理所有的实例。

    注意:类锁修饰方法和代码块的效果和对象锁是一样的,因为类锁只是一个抽象出来的概念,只是为了区别静态方法的特点,因为静态方法是所有对象实例共用的,所以对应着synchronized修饰的静态方法的锁也是唯一的,所以抽象出来个类锁。

    可以参考这个链接:https://www.cnblogs.com/nn369/p/8043303.html

    其中第一个示例里如果把this 改为 Bank.class ,你会看到效果的不同。

    同步方法与同步代码块:

    public synchronized void produce(){
        // TODO      

    同步方法:

    针对某个方法进行同步,意味着如果获得获得锁后必须执行完这个方法,才会释放锁,如果里面要处理的东西非常多,会很影响性能。针对高并发有可能会导致系统崩溃,

    如果某个线程在同步方法里面发生了死循环,那么它就永远不会释放这个对象锁,那么其他线程就要永远的等待。

    同步代码块:

    同步代码块会只针对其中某一块代码加锁,这样如果我们把最需要同步的地方加上锁就可以,比如核心运算,这样会降低系统崩溃的风险。

    比如一个厕所有1个坑,厕所大家可以都进来(房间不加锁),之前的买票大家可以同时买了,都是1块钱一个人,那么等待坑上那个人(线程)解决之后,下一个人就可以直接上了~ 不用再去票再进来了,这样会提高一些效率,省去买票的时间。

    或者说,票还是+1 块钱,这样买完票的可以直接进入房间,也不用非得等到里面的人出来再进入了。(~~)

    而且同步代码块可以指定对象锁,就好像只能钥匙一样,不一定是当前对象的内置锁,也可以是其他对象锁。

    就比如:厕所门的锁需要去公园管理处拿一样,在厕所门口的售票处是没有这个门的锁的。

    成灰之前,抓紧时间做点事!!
  • 相关阅读:
    Redis笔记 —— string 篇
    解决跨域请求无法携带Cookie的问题
    Mysql事务学习笔记
    Redis笔记 —— hash 篇
    mysql视图的简单学习
    axios无法被识别为ajax请求的解决方案
    常见header信息详解
    int 15h
    操作系统有进程了
    是时候走我自己的路线了,真正的做我自己的Jinux
  • 原文地址:https://www.cnblogs.com/jony-it/p/10764482.html
Copyright © 2011-2022 走看看