zoukankan      html  css  js  c++  java
  • 【java】锁对象状态的改变会导致非线程安全

    问题描述

    使用synchronized在一个非final对象上加了锁之后,在synchronized体(同步代码块)中,将该对象的值(状态)改变之后,会导致线程不安全,即其他线程会拿到改变之后对象的锁,从而进入同步代码块。

    场景设计

    public class TestLock extends Thread{
        private AAA aaa;
         
        public TestLock(AAA aaa) {
            this.aaa = aaa;
        }
     
        @Override
        public void run() {
            this.aaa.lockMethod();
        }
     
        public static void main(String[] args) {
            AAA aaa = new AAA();
            Thread a1 = new TestLock(aaa);
            Thread a2 = new TestLock(aaa);
            a1.start();
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            a2.start();
        }
    }
     
    class AAA{
        private Boolean lock = true;
     
        public void lockMethod() {
            synchronized (lock) {
                lock = !lock;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(lock);
            }
        }
    }

    场景说明

    两个线程a1,a2,访问同一个AAA对象aaa(临界资源),AAA中的lockMethod方法中是一个同步代码块,锁加在非final的lock对象上,在同步代码块中改变lock对象的值。main函数中500ms的休眠是能够让线程a1先获得lock的锁,线程a1先访问同步代码块,将lock的值变成false,接着休眠一秒。

    假设

    如果lock值的改变不会影响线程安全的特性,那么线程a2拿不到lock的锁,在休眠结束之后,应该输出false,然后,线程a2拿到lock锁,进入同步代码块,将lock的值变成true,然后休眠一秒,休眠结束后,输出lock的值true,即输出的两个值是false和true。

    程序运行结果

    true和true

    程序结果分析

    第一个的输出结果是true,说明,线程a1进入同步代码块之后,将lock的值变成false,进入休眠,线程a2能够拿到修改后的lock对象的锁,进入同步代码块,将lock的值变成true,然后线程a2进入休眠,线程a1休眠结束之后,输出被线程a2修改之后的lock值true,然后,线程a2休眠结束之后,同样输出true,符合程序输出结果。

    总结与注意

    对于非对象上的锁,在同步代码块中修改起状态后,会导致线程不安全,即其他线程会拿到修改后的对象上的锁。

    对于需要加锁的对象,可以设置成final,这样就避免了对其的修改,如果是非final的对象,需要做到在同步块中避免对锁对象的修改。

  • 相关阅读:
    什么是语义化的HTML?有何意义?为什么要做到语义化?
    Doctype作用?严格模式与混杂模式如何区分?它们有何差异?
    js和jq中常见的各种位置距离之offsetLeft和position().left的区别(四)
    js和jq中常见的各种位置距离之offset和offset()的区别(三)
    js和jq中常见的各种位置距离之offset()和position()的区别(二)
    js和jq中常见的各种位置距离之offsetLeft/clientLeft/scrollLeft (一)
    剖析js中的数据类型
    js数组去重几种方法
    SSE and Websocket
    鲜为人知的空元素╮(╯▽╰)╭
  • 原文地址:https://www.cnblogs.com/sqdmydxf/p/7767823.html
Copyright © 2011-2022 走看看