一张图讲解对象锁和关键字synchronized修饰方法(代码块)

来源:互联网 发布:java 计算两个时间差 编辑:程序博客网 时间:2024/06/03 12:51

分类:

    每个对象在出生的时候就有一把钥匙(监视器Monitor),那么被synchronized 修饰的方法相当于给方法加了一个锁,这个方法就可以进行同步,在多线程的时候,不会出现线程安全问题。

    注:Monitor是 Java中用以实现线程之间的互斥与协作的主要手段,它可以看成是对象或者 Class的锁。每一个对象都有,也仅有一个 Monitor。

    下面通过一张图片进行讲解:

    1.一张图片

    图片看不清,请点击这里 : 高清大图

    这里写图片描述

    2.图片对应的代码

    import java.util.Date;/** * 测试的object类 * * @author:dufy * @version:1.0.0 * @date 2017/9/29 * @email 742981086@qq.com */public class ObjectTest {    public synchronized  void methodA(){        try {            System.out.println("This is methodA ...." + Thread.currentThread().getName() + ": " + new Date());            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }    public void methodB(){        System.out.println("This is methodB ...." + Thread.currentThread().getName() + ": " + new Date());    }    public synchronized void methodC(){        try {            System.out.println("This is methodC ...." + Thread.currentThread().getName() + ": " + new Date());            Thread.sleep(3000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    package com.dufy.concurrentcode;/** * 测试线程类 * * @author:dufy * @version:1.0.0 * @date 2017/9/29 * @email 742981086@qq.com */public class ThreadTest extends Thread{    public static void main(String[] args) {        ObjectTest ot = new ObjectTest();        Thread1 t1 = new Thread1(ot,"thread1");        Thread2 t2 = new Thread2(ot,"thread2");        Thread3 t3 = new Thread3(ot,"thread3");        Thread4 t4 = new Thread4(ot,"thread4");        t1.start();        t2.start();        t3.start();        t4.start();    }    static class Thread1 extends Thread{        private ObjectTest objectTest;        public Thread1(ObjectTest objectTest,String name){            setName(name);            this.objectTest = objectTest;        }        @Override        public void run() {            super.run();            objectTest.methodA();        }    }    static class Thread2 extends Thread{        private ObjectTest objectTest;        public Thread2(ObjectTest objectTest,String name){            setName(name);            this.objectTest = objectTest;        }        @Override        public void run() {            super.run();            objectTest.methodB();        }    }    static class Thread3 extends Thread{        private ObjectTest objectTest;        public Thread3(ObjectTest objectTest,String name){            setName(name);            this.objectTest = objectTest;        }        @Override        public void run() {            super.run();            objectTest.methodA();        }    }    static class Thread4 extends Thread{        private ObjectTest objectTest;        public Thread4(ObjectTest objectTest,String name){            setName(name);            this.objectTest = objectTest;        }        @Override        public void run() {            super.run();            objectTest.methodC();        }    }}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    运行结果:

    This is methodB ....thread2: Fri Sep 29 23:21:17 CST 2017This is methodA ....thread1: Fri Sep 29 23:21:17 CST 2017This is methodC ....thread4: Fri Sep 29 23:21:18 CST 2017This is methodA ....thread3: Fri Sep 29 23:21:21 CST 2017
    • 1
    • 2
    • 3
    • 4

    注:
    1、运行的结果可能和上图讲的线程流程不同,没有关系,只要理解对象锁和synchronized的核心思想就好,线程的运行本来就是具有随机性这个特点。

    2、此段代码是同步方法,其实同步的代码块也是一个道理,同步代码块用synchronized(this)时候,当一个线程访问object的一个synchronized(this)同步代码块的时候,其他线程对object中所有其他的synchronized(this)同步的代码块访问都被阻塞(阻塞的是同步代码块,线程依然可以进入同步代码块的方法)

    3.总结

    1. 每个对象都有一把锁(对象监视器),关键字synchronized取得锁都是对象锁,而不是把一段代码或方法(函数)当做锁。
    2. 上图所示,哪个线程先执行带有synchronized关键字的方法,哪个线程就持有这个方法所属对象的钥匙。其他线程只能处于等待状态。
    3. 调用关键字synchronized声明的方法,一定是排队运行的。这才是使用synchronized关键字的作用,排队运行,如果有共享资源的话,那么共享资源的读取就是线程安全的。
    4. 如果一个线程持有 object的钥匙,那么其他线程可以访问object对象没有上锁的方法,也就是非synchronized类型的方法。

    4.Monitor和线程关系

    首先看一下线程和 Monitor之间关系,以 及线程的状态转换图。通过图讲解一下整个过程。

    这里写图片描述

    上图分为三块:Entry Set(进入区) 、The Owner(拥有区)、Wait Set(等待区)。

    • Entry Set(进入区):表示线程通过synchronized要求获取对象的锁。如果对象未被锁住,则迚入拥有者;否则则在进入区等待。一旦对象锁被其他线程释放,立即参与竞争。

    • The Owner(拥有区):表示某一线程成功竞争到对象锁。

    • Wait Set(等待区):表示线程通过对象的wait方法,释放对象的锁,并在等待区等待被唤醒。

    从图中可以看出,一个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。

    上面的内容讲解引自 :Java命令学习系列(二)——Jstack 中关于Monitor的讲解。

    5.参考

    Java多线程编程核心技术



    如果帅气(美丽)、睿智(聪颖),和我一样简单善良的你看到本篇博文中存在问题,请指出,我虚心接受你让我成长的批评,谢谢阅读!
    祝你今天开心愉快!


    欢迎访问我的csdn博客,我们一同成长!

    不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

    博客首页:http://blog.csdn.net/u010648555

    阅读全文
    0 0
    原创粉丝点击