山西晋城一周天气预报:java多线程4:synchronized关键字

admin 3个月前 (08-11) 科技 56 1

概述

  java有林林总总的锁,而且每种锁的特征差别,合理场景下行使锁可以展现出异常高的效率。synchronized内置锁就是Java的一种重量级锁,它能够解决并发编程中泛起多个线程同时接见一个共享,可变的临界资源时泛起的线程安全问题。让多个线程序列化接见临界资源,统一时刻,只能有一个线程接见临界资源,同步互斥,这样就保证了操作的原子性。

synchronized使用

同步方式块

public class ThreadDemo5 implements Runnable{

    private int count = 0;

    @Override
    public void run() {
        synchronized (this){
            for (int i = 0; i < 10; ++i){
                count++;
                System.out.println("执行的线程是=>" + Thread.currentThread().getName() + "执行效果为->" + count);
            }
        }

    }

    public static void main(String[] args) {
        ThreadDemo5 threadDemo5 = new ThreadDemo5();
        Thread thread1 = new Thread(threadDemo5,"thread1");
        Thread thread2 = new Thread(threadDemo5,"thread2");
        thread1.start();
        thread2.start();
    }
}

执行效果

执行的线程是=>thread1执行效果为->1
执行的线程是=>thread1执行效果为->2
执行的线程是=>thread1执行效果为->3
执行的线程是=>thread1执行效果为->4
执行的线程是=>thread1执行效果为->5
执行的线程是=>thread1执行效果为->6
执行的线程是=>thread1执行效果为->7
执行的线程是=>thread1执行效果为->8
执行的线程是=>thread1执行效果为->9
执行的线程是=>thread1执行效果为->10
执行的线程是=>thread2执行效果为->11
执行的线程是=>thread2执行效果为->12
执行的线程是=>thread2执行效果为->13
执行的线程是=>thread2执行效果为->14
执行的线程是=>thread2执行效果为->15
执行的线程是=>thread2执行效果为->16
执行的线程是=>thread2执行效果为->17
执行的线程是=>thread2执行效果为->18
执行的线程是=>thread2执行效果为->19
执行的线程是=>thread2执行效果为->20

 同步方式块,synchronized锁的是括号里的工具,每个线程要进入代码块前必须先获取工具的的锁,才可执行。synchronized是一个隐式锁,也是jvm内置的锁,它会自动加锁和解锁,同时java的每个工具都可以作为锁。

通俗同步方式

public class ThreadDemo6 implements Runnable {

    private int count = 0;

    @Override
    public void run() {
        say();
    }

    private synchronized void say(){
        for (int i = 0; i < 10; ++i){
            count++;
            System.out.println("现在执行的线程执行=>" + Thread.currentThread().getName() + "效果为->" + count);
        }
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ThreadDemo6 threadDemo6 = new ThreadDemo6();
        Thread thread1 = new Thread(threadDemo6,"Thread-1");
        Thread thread2 = new Thread(threadDemo6,"Thread-2");
        thread1.start();
        thread2.start();
    }
}

执行效果

现在执行的线程执行=>Thread-1效果为->1
现在执行的线程执行=>Thread-1效果为->2
现在执行的线程执行=>Thread-1效果为->3
现在执行的线程执行=>Thread-1效果为->4
现在执行的线程执行=>Thread-1效果为->5
现在执行的线程执行=>Thread-1效果为->6
现在执行的线程执行=>Thread-1效果为->7
现在执行的线程执行=>Thread-1效果为->8
现在执行的线程执行=>Thread-1效果为->9
现在执行的线程执行=>Thread-1效果为->10
/*停留5秒*/ 现在执行的线程执行=>Thread-2效果为->11 现在执行的线程执行=>Thread-2效果为->12 现在执行的线程执行=>Thread-2效果为->13 现在执行的线程执行=>Thread-2效果为->14 现在执行的线程执行=>Thread-2效果为->15 现在执行的线程执行=>Thread-2效果为->16 现在执行的线程执行=>Thread-2效果为->17 现在执行的线程执行=>Thread-2效果为->18 现在执行的线程执行=>Thread-2效果为->19 现在执行的线程执行=>Thread-2效果为->20

通俗同步方式,通过例子可以知道他是一个工具锁,线程1未释放锁,线程2只能被动守候,改下代码

 public static void main(String[] args) {
        Thread thread1 = new Thread(new ThreadDemo6(),"Thread-1");
        Thread thread2 = new Thread(new ThreadDemo6(),"Thread-2");
        thread1.start();
        thread2.start();
    }

执行效果

现在执行的线程执行=>Thread-2效果为->1
现在执行的线程执行=>Thread-2效果为->2
现在执行的线程执行=>Thread-2效果为->3
现在执行的线程执行=>Thread-2效果为->4
现在执行的线程执行=>Thread-2效果为->5
现在执行的线程执行=>Thread-2效果为->6
现在执行的线程执行=>Thread-2效果为->7
现在执行的线程执行=>Thread-2效果为->8
现在执行的线程执行=>Thread-2效果为->9
现在执行的线程执行=>Thread-2效果为->10
现在执行的线程执行=>Thread-1效果为->1
现在执行的线程执行=>Thread-1效果为->2
现在执行的线程执行=>Thread-1效果为->3
现在执行的线程执行=>Thread-1效果为->4
现在执行的线程执行=>Thread-1效果为->5
现在执行的线程执行=>Thread-1效果为->6
现在执行的线程执行=>Thread-1效果为->7
现在执行的线程执行=>Thread-1效果为->8
现在执行的线程执行=>Thread-1效果为->9
现在执行的线程执行=>Thread-1效果为->10
停留。。

不是统一个工具锁,以是线程1和线程2不存在锁的互斥,而且不存在共享资源count变量,以是多个线程接见的必须是统一个工具,锁才会变得有意义。

静态同步方式

public class ThreadDemo6 implements Runnable {

    private static int count = 0;

    @Override
    public void run() {
        say();
    }

    private static synchronized void say(){
        for (int i = 0; i < 10; ++i){
            count++;
            System.out.println("现在执行的线程执行=>" + Thread.currentThread().getName() + "效果为->" + count);
        }
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        Thread thread1 = new Thread(new ThreadDemo6(),"Thread-1");
        Thread thread2 = new Thread(new ThreadDemo6(),"Thread-2");
        thread1.start();
        thread2.start();
    }
}

执行效果

现在执行的线程执行=>Thread-1效果为->1
现在执行的线程执行=>Thread-1效果为->2
现在执行的线程执行=>Thread-1效果为->3
现在执行的线程执行=>Thread-1效果为->4
现在执行的线程执行=>Thread-1效果为->5
现在执行的线程执行=>Thread-1效果为->6
现在执行的线程执行=>Thread-1效果为->7
现在执行的线程执行=>Thread-1效果为->8
现在执行的线程执行=>Thread-1效果为->9
现在执行的线程执行=>Thread-1效果为->10
/*停留*/
现在执行的线程执行=>Thread-2效果为->11
现在执行的线程执行=>Thread-2效果为->12
现在执行的线程执行=>Thread-2效果为->13
现在执行的线程执行=>Thread-2效果为->14
现在执行的线程执行=>Thread-2效果为->15
现在执行的线程执行=>Thread-2效果为->16
现在执行的线程执行=>Thread-2效果为->17
现在执行的线程执行=>Thread-2效果为->18
现在执行的线程执行=>Thread-2效果为->19
现在执行的线程执行=>Thread-2效果为->20

纵然他们是差别的工具,但执行的都是一个类的方式,在执行同步静态方式时,争抢的是类锁,这也是和非静态同步方式所区别开来。由于他们是两个差别的锁,一个是工具锁,一个是类锁。以是,在代码中,一个线程可以同时抢有工具锁,类锁。

 monitor和monitorexit

Java的互斥锁是若何的实现的,javap -verbose ThreadDemo3.class 看下字节码子令。

同步代码块

   

 非静态方式同步

 

 

 静态方式同步

 

 同步块中monitor被占用就处于锁定状态,其他本次抢锁失败的线程将会放入Wait Set守候同步行列中举行守候,占用锁的线程执行完同步块而且释放锁后将会通知放入同步行列的的其他线程,通知他们,我释放锁了赶快来抢吧!而相对于通俗的静态同步方式和非静态同步方式,常量池汇中多了ACC_SYNCHRONIZED符号,方式挪用就会去检查是不是有这个符号若是有,jvm就会要求线程在挪用前先请求锁,但无论哪种实现,在实质上照样通过工具相关联的的monitor获取的。

而monitor是什么哪?它是每个工具建立之后都市在jvm内部维护一个与之对应Monitor(监视器锁)也有人叫管程横竖都是一个器械,可以理解为每个工具天生都有一把看不见的锁我们叫他monitor锁,而每个线程会有一个可用的MR(Monitor Record)列表,另有一个全局可用列表,每一个被锁住的工具都市和一个MR相关联,而且工具monitor中会有一个owner字段存放占用该锁线程唯一标识,示意这个锁已经被哪个线程占用,synchronized就是基于进入与退出Monitor工具实现方式与代码块同步,而监视器锁的实现哪是依赖底层操作系统Mutex lock(互斥锁),它是一个重量级锁,每次从用户态切换到内的态的资源消耗是比较大的,也因此从jdk1.6后,java对synchronized举行了优化,从一最先的无锁状态->偏向锁状态->轻量级锁状态->重量级锁状态,而且这个状态是不可逆的。

jvm加锁历程

 

 

 工具内存结构

 上文说过每个Java工具都是天生的锁,存放在Java的工具头中,工具头包罗三个区域,工具头,实例数据,补齐填充

第一部门是存储工具自身运行时的数据,哈希码,GC,偏向时间戳,保留工具的分代岁数,锁状态标志,偏向锁线程id,线程持有的锁,若是是数组还需要一块区域存放数组巨细,class的工具指针是虚拟机通过他确定这个工具是哪个类的实例,我们平时getClass直接获取类就跟这个有关,官方称这部门为Mark Word,第二部门略过,第三部门划定工具的巨细必须是8字节的整数倍,至于为什么,lz没去深究暂时不知道。我们重点关注是Mark Word的锁标志位,以是锁的状态是保留在工具头中的,至于偏向状态,篇幅有限,下节在谈。

锁的粗化和消除

锁的粗化

锁带来性能开销是很大的,为了保证多线程的并发操作,通常会要求每个线程持有锁的时间越短越好,但若是遇到一连串对统一把锁举行请求和释放的操作,jvm会举行优化智能的把锁操作的整合成一个较大同步块,从而减少了对锁的频仍申请和释放提高性能。

public class ThreadDemo7 implements Runnable {
    public void test(){
        synchronized (this){
            System.out.println(1111);
        }
        synchronized (this){
            System.out.println(222);
        }
        synchronized (this){
            System.out.println(333);
        }
    }
    public static void main(String[] args) {
        ThreadDemo7 threadDemo7 = new ThreadDemo7();
        Thread thread = new Thread(threadDemo7);
        thread.start();
    }

    @Override
    public void run() {
        test();
    }
}

锁的消除

我们设置了同步块,在字节码中也发现了monitorenter和monitorexit,至少看上去有锁的获取和释放历程,但执行的效果与我们展望的风马牛不相及。

public class ThreadDemo8 implements Runnable {
    private static int count = 0;
    @Override
    public void run() {
        synchronized (new Object()){
            count++;
            System.out.println("锁的消除...=>"  + Thread.currentThread().getName() + "值=>" + count);
        }
    }

    public static void main(String[] args) {
        ThreadDemo8 threadDemo8 = new ThreadDemo8();
        for (int i = 0; i < 10; ++i){
            Thread thread = new Thread(threadDemo8);
            thread.start();
        }
    }

}

执行效果

锁的消除...=>Thread-6值=>4
锁的消除...=>Thread-4值=>2
锁的消除...=>Thread-5值=>4
锁的消除...=>Thread-0值=>4
锁的消除...=>Thread-1值=>6
锁的消除...=>Thread-2值=>6
锁的消除...=>Thread-3值=>7
锁的消除...=>Thread-9值=>8
锁的消除...=>Thread-7值=>9
锁的消除...=>Thread-8值=>10

这是由于jit在编译代码时,使用了逃逸剖析的手艺,判断程序中的使用锁的工具是否被其他线程使用,若是只被一个线程使用,这个同步代码就不会天生synchronized锁标识的锁申请和释放的机器码,消除了锁的使用流程。以是,并不是所有的实例工具都存放在堆区,若是发生线程逃逸行为,将会存储在线程栈上。

总结

锁的重入和锁膨胀升级,在后期在逐步整理。

参考

https://blog.csdn.net/axiaoboge/article/details/84335452

https://www.cnblogs.com/xrq730/p/4853578.html

 

,

Sunbet 申博

Sunbet 申博www.sunbet88.us是Sunbet指定的Sunbet官网,Sunbet提供Sunbet(Sunbet)、Sunbet、申博代理合作等业务。

阳光在线声明:该文看法仅代表作者自己,与本平台无关。转载请注明:山西晋城一周天气预报:java多线程4:synchronized关键字

网友评论

  • (*)

最新评论

  • Allbet代理 2020-08-11 00:06:21 回复

    SunbetSunbet是菲律宾sunbet官网线上游戏直营平台,提供sunbet开户、sunbet下载等服务。Sunbet在2019年里将贯彻执行公司企业文化:诚信、服务。熬夜追完了

    1

站点信息

  • 文章总数:334
  • 页面总数:0
  • 分类总数:8
  • 标签总数:479
  • 评论总数:159
  • 浏览总数:2969

标签列表