zoukankan      html  css  js  c++  java
  • 线程安全、类锁、对象锁

    文章目录
    文章思路
    synchronized作用
    锁和synchronized的关系
    synchronized有几种用法
    锁有几种
    对象锁和类锁的使用
    文章思路
    哪些概念难理解
    类锁和对象锁区别
    类锁所有对象一把锁
    对象锁一个对象一把锁,多个对象多把锁
    同步是对同一把锁而言的,同步这个概念是在多个线程争夺同一把锁的时候才能实现的,如果多个线程争夺不同的锁,那多个线程是不能同步的
    两个线程一个取对象锁,一个取类锁,则不能同步
    两个线程一个取a对象锁,一个取b对象锁,则不能同步
    文章关键内容:
    什么是锁
    锁有几种
    什么是synchronized
    synchronized用法
    用于方法
    得到类锁
    得到对象锁
    用与代码块
    得到类锁
    得到对象锁
    两种锁的使用
    synchronized作用
    synchronized是用来完成多线程条件下同步工作的

    若没有同步,一个方法有多条语句,两个线程A和B都要都用某个方法,而A线程在调用这个方法的时候,B线程可不会等它多条语句都执行完再去调用这个方法,更有可能的是A线程没有执行完这个方法,B线程夺得CPU执行权,A对这个方法的调用就停止在它最后执行到的语句位置,直到A下一次抢到CPU执行权A才能继续执行它未执行完的代码。

    有了同步后,当A获得执行权并开始执行此方法,B就必须乖乖等A将方法全部执行完之后才有权去执行此方法。

    锁和synchronized的关系
    锁是Java中用来实现同步的工具
    而之所以能对方法或者代码块实现同步的原因就是
    只有拿到锁的线程才能执行synchronized修饰的方法或代码块,且其他线程获得锁的唯一方法是等目前拿到锁的线程执行完方法将锁释放,如果synchronized修饰的代码块或方法没执行完是不会释放这把锁的,这就保证了拿到锁的线程一定可以一次性把它调用的方法或代码块执行完

    synchronized有几种用法
    用于方法

    class B {
    //在方法前面加上synchronized关键字表示作用于该方法
    //需要注意方法有两种,一种静态方法,一种非静态方法
    //两者区别在于,当修饰静态时候,大家都调用的是同一个。当修饰非静态方法时候,调用的是每个对象自己的那个方法,因为非静态域或方法是每个对象各自都有一份的,静态方法是所有对象公有的。
    synchronized public static void mB(String value) throws InterruptedException {
    for (int i = 0; i < 1000; i++) {
    System.out.print(value);
    }
    }
    synchronized public void mC(String value) throws InterruptedException {
    for (int i = 0; i < 1000; i++) {
    System.out.print(value);
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    用于代码块


    class A {
    public static void test() {
    //修饰代码块的情况也有两种,这里表示对类进行同步
    synchronized (A.class) {
    System.out.println("haha");
    }
    }
    public void test2() {
    //这里表示对当前对象进行同步,两者区别看下面锁有几种
    synchronized (this) {
    System.out.println("haha");
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    锁有几种
    类锁
    类锁,是用来锁类的,我们知道一个类的所有对象共享一个class对象,共享一组静态方法,类锁的作用就是使持有者可以同步地调用静态方法。当synchronized指定修饰静态方法或者class对象的时候,拿到的就是类锁,类锁是所有对象共同争抢一把。

    //B中有两个方法mB和mC
    //mB是synchronized修饰静态方法,拿到类锁
    //mC是synchronized修饰非静态方法,拿到的也是类锁
    class B {
    synchronized public static void mB(String value) throws InterruptedException {
    for (int i = 0; i < 1000; i++) {
    System.out.print(value);
    }
    }

    public void mC(String value) {
    synchronized (B.class) {
    for (int i = 0; i < 1000; i++) {
    System.out.print(value);
    }
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    对象锁
    对象锁,是用来对象的,虚拟机为每个的非静态方法和非静态域都分配了自己的空间,不像静态方法和静态域,是所有对象共用一组。
    所以synchronized修饰非静态方法或者this的时候拿到的就是对象锁,对象锁是每个对象各有一把的,即同一个类如果有两个对象。

    //类C中有两个方法mB和mC
    //mB是synchronized非静态方法,拿到对象锁
    //mC是synchronized修饰this,拿到的也是对象锁
    class C {
    synchronized publi void mB(String value) throws InterruptedException {
    for (int i = 0; i < 1000; i++) {
    System.out.print(value);
    }
    }

    public void mC(String value) {
    synchronized (this) {
    for (int i = 0; i < 1000; i++) {
    System.out.print(value);
    }
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    对象锁和类锁的使用
    对象锁
    下例中,两个线程调用同一个对象b的mB方法。最终结果是输出了1000次“1”之后输出了1000次“2”。可见两个线程对此方法的调用实现了同步。

    class B {
    //修饰非静态方法拿到对象锁
    synchronized public void mB(String name) throws InterruptedException {
    for (int i = 0; i < 1000; i++) {
    System.out.print(name);
    }
    }
    //修饰this拿到对象锁
    public void mB2(String name) throws InterruptedException {
    synchronized(this) {
    for (int i = 0; i < 1000; i++) {
    System.out.print(name);
    }
    }
    }
    }

    public class test {

    public static void main(String[] args) {

    B b = new B();
    Thread thread1 = new Thread(new Runnable() {
    @Override
    public void run() {
    try {
    //线程1的调用处
    b.mB("1");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    });
    Thread thread2 = new Thread(new Runnable() {
    @Override
    public void run() {
    try {
    //线程2的调用处
    b.mB2("2");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    });
    thread1.start();
    thread2.start();
    }
    }
    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
    类锁
    下面代码中对静态方法mA和mC的调用实现了同步,结果没有交替输出1和2,而是一次性输出完成后再输出的另一种

    class B {
    //修饰静态方法,调用取得类锁
    synchronized public static void mB(String value) throws InterruptedException {
    for (int i = 0; i < 1000; i++) {
    System.out.print(value);
    }
    }
    //修饰class对象,调用取得静类锁
    public static void mC(String value) {
    synchronized (B.class) {
    for (int i = 0; i < 1000; i++) {
    System.out.print(value);
    }
    }
    }

    public static void main(String[] args) {

    Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
    try {
    B.mB("1");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    }
    });
    Thread thread2 = new Thread(new Runnable() {
    @Override
    public void run() {
    B.mC("2");
    }
    });
    }
    }
    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
    类锁和对象锁同时存在
    同时存在的情况下,两者做不到同步。类锁和对象锁是两种锁。下述情况,类B的静态方法和代码块功能都是打印100个value值,但是静态方法是类锁,而代码块锁this,是对象锁。所以代码块和静态方法交替执行、交替打印,大家可复制代码自行验证。

    class B {
    //静态方法,上类锁,函数功能为连续打印1000个value值,调用时会传1,所以会打印1000个1
    synchronized public static void mB(String value) throws InterruptedException {
    for (int i = 0; i < 1000; i++) {
    System.out.print(value);
    Thread.sleep(100);
    }
    }

    public void mC(String value) {
    //修饰this上对象锁,函数功能也是连续打印1000个value值,调用时会传2,所以会打印1000个2
    synchronized (this) {
    for (int i = 0; i < 1000; i++) {
    System.out.print(value);
    Thread.sleep(100);
    }
    }
    }

    public static void main(String[] args) {

    Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
    try {
    B.mB("1");

    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    }
    });
    B b = new B();
    Thread thread2 = new Thread(new Runnable() {
    @Override
    public void run() {
    b.mC("2");
    }
    });
    thread.start();
    thread2.start();

    }
    }
    ————————————————
    版权声明:本文为CSDN博主「TesuZer」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/TesuZer/article/details/80874195

  • 相关阅读:
    iframe高度自适应方法
    mysql left join对于索引不生效的问题
    禁止百度转码和百度快照缓存的META声明
    使用graphviz绘制流程图
    安装php扩展sphinx-1.2.0.tgz和libsphinxclient0.9.9
    5种主要的编程风格和它们使用的抽象
    Nodejs调用Aras Innovator服务,处理AML并返回AML
    使用Rancher管理Docker
    docker容器间通信
    使用Portainer管理Docker
  • 原文地址:https://www.cnblogs.com/xyzq/p/11416978.html
Copyright © 2011-2022 走看看