关于JAVA里的加锁synchronized

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于JAVA里的加锁synchronized相关的知识,希望对你有一定的参考价值。

public class TT implements Runnable
int b = 100;

public synchronized void m1() throws Exception
b = 1000;
Thread.sleep(5000);
System.out.println("b = " + b);


public void m2()

System.out.println(b);


public void run()
try
m1();
catch(Exception e)
e.printStackTrace();



public static void main(String[] args) throws Exception
TT tt = new TT();
Thread t = new Thread(tt);
t.start();
Thread.sleep(1000);
tt.m2();



这个程序tt.m2()没有调用m1方法,而且当t线程进行时已经把m1锁定,为什么m2方法的println
b=1000而不是100,锁定的意思不就是不允许其他线程访问锁定的方法和方法里的对象么?

1.凡使用synchronized标记的方法,比如 public synchronized void func1() .... ,则同时只有一个线程能够运行这个方法。比如,线程1正在运行func1,则其他线程需要运行func1的话,会卡住,等线程1运行func1结束后,其他线程中,才会有一个幸运儿成功争取到运行func1的资格,然后这个幸运儿线程开始运行func1。没有争取到运行资格的其他线程,会继续等待。

2.你的例子中,被锁定的是 方法 m1,而不是属性b。所以,m1的synchronized加锁操作,与b没有半点毛钱关系。

3.要实现你的锁b想法,其实很简单。去买一件贞操宝甲来就行了。开玩笑,哈哈。要锁b,把main方法里的tt.m2()修改为tt.m1()。

4.以后别用“b”作为变量,总觉得怪怪了。也许你现在还没长大,很单纯。但大人的世界里,“b”是一种不文雅但又对人类的未来有重要作用的东西。建议用cb来代替b。追问

哈哈,我只是刚开始学基础而已,看到这个不是很明白,你的意思就是加锁后别的进程仍可以读取出加锁方法里重新定义的变量是么?
而且加锁的意思不就是把当前方法锁住别的进程不能再读了么?

追答

    我已经说的很清楚了。你的问题,上面的解释已经都讲明白了。你需要再去看看我在上面的解释。

    你提这个问题,说明你根本就没有认真去看我上面写的东西,也没有仔细去理解。

    现在你要做的事情就是,静下心来,认真的把我上面写的东西,看一遍。一遍看不懂,再看几遍。在看的同时,也要去自己写写java代码,做一下实验。

追问

我的意思是 当t.start()线程开始时,把m1方法锁住,别的线程不能访问,b = 1000了 然后sleep5秒,这时候main主线程调用m2方法,
m2方法怎么会知道已经锁住的方法里的赋值的?

参考技术A synchronized具有可见性和原子性。你把m1锁了,里面的b就对其他线程可见。可见的意思就是只要你在锁的代码里改变了b的值,别的线程就会知道b的值改变了并进行同步。具体过程看java内存模型JMM。所以tt执行m2时同步了b的值进行输出。顺带说一句,你m1是新建的子线t程执行,m2是在主线程main执行。 参考技术B Thread.sleep操作线程能够将变量的修改同步到主存中。

以上是关于关于JAVA里的加锁synchronized的主要内容,如果未能解决你的问题,请参考以下文章

JDK源码笔记之Integer深度解析以及并发下错误的加锁方式踩坑笔记

Java程序员必备!MySQL:介于普通读和锁定读的加锁方式

使用guava进行对字符串的加锁

Java程序员必会!MySQL:介于普通读和锁定读的加锁方式

MySQL普通索引的加锁

2.8.4 错误的加锁