扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
本篇内容主要讲解“Java并发synchronized用在方法上锁住的内容是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java并发synchronized用在方法上锁住的内容是什么”吧!
公司主营业务:成都做网站、网站设计、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。创新互联是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。创新互联推出武都免费做网站回馈大家。
synchronized用在方法上锁住的是什么?
锁住的是当前对象的当前方法,会使得其他线程访问该对象的synchronized方法或者代码块阻塞,但并不会阻塞非synchronized方法。
脏读
一个常见的概念。在多线程中,难免会出现在多个线程中对同一个对象的实例变量或者全局静态变量进行并发访问的情况,如果不做正确的同步处理,那么产生的后果就是"脏读",也就是取到的数据其实是被更改过的。注意这里 局部变量是不存在脏读的情况
public class ThreadDomain13 { private int num = 0; public void addNum(String userName) { try { if ("a".equals(userName)) { num = 100; System.out.println("a set over!"); Thread.sleep(2000); } else { num = 200; System.out.println("b set over!"); } System.out.println(userName + " num = " + num); } catch (InterruptedException e) { e.printStackTrace(); } } }
写两个线程分别去add字符串"a"和字符串"b":
public class MyThread13_0 extends Thread { private ThreadDomain13 td; public MyThread13_0(ThreadDomain13 td) { this.td = td; } public void run() { td.addNum("a"); } } public class MyThread13_1 extends Thread { private ThreadDomain13 td; public MyThread13_1(ThreadDomain13 td) { this.td = td; } public void run() { td.addNum("b"); } }
写一个主函数分别运行这两个线程:
public static void main(String[] args) { ThreadDomain13 td = new ThreadDomain13(); MyThread13_0 mt0 = new MyThread13_0(td); MyThread13_1 mt1 = new MyThread13_1(td); mt0.start(); mt1.start(); } //看一下运行结果 a set over! b set over! b num = 200 a num = 200
按照正常来看应该打印"a num = 100"和"b num = 200"才对,现在却打印了"b num = 200"和"a num = 200",这就是线程安全问题。我们可以想一下是怎么会有线程安全的问题的:
1、mt0先运行,给num赋值100,然后打印出"a set over!",开始睡觉
2、mt0在睡觉的时候,mt1运行了,给num赋值200,然后打印出"b set over!",然后打印"b num = 200"
3、mt1睡完觉了,由于mt0的num和mt1的num是同一个num,所以mt1把num改为了200了,mt0也没办法,对于它来说,num只能是100,mt0继续运行代码,打印出"a num = 200"
分析了产生问题的原因,解决就很简单了,给addNum(String userName)方法加同步即可:
多线程线synchronized关键字加到方法上
public class ThreadDomain13 { private int num = 0; public synchronized void addNum(String userName) { try { if ("a".equals(userName)) { num = 100; System.out.println("a set over!"); Thread.sleep(2000); } else { num = 200; System.out.println("b set over!"); } System.out.println(userName + " num = " + num); } catch (InterruptedException e) { e.printStackTrace(); } } }
看一下运行结果:
a set over! a num = 100 b set over! b num = 200
多个对象多个锁
在同步的情况下,把main函数内的代码改一下:
public static void main(String[] args) { ThreadDomain13 td0 = new ThreadDomain13(); ThreadDomain13 td1 = new ThreadDomain13(); MyThread13_0 mt0 = new MyThread13_0(td0); MyThread13_1 mt1 = new MyThread13_1(td1); mt0.start(); mt1.start(); }
看一下运行结果:
a set over! b set over! b num = 200 a num = 100
这里有一个重要的概念。关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当作锁,这里如果是把一段代码或方法(函数)当作锁,其实获取的也是对象锁,只是监视器(对象)不同而已,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁,其他线程都只能呈等待状态。但是这有个前提:既然锁叫做对象锁,那么势必和对象相关,所以多个线程访问的必须是同一个对象。
如果多个线程访问的是多个对象,那么Java虚拟机就会创建多个锁,就像上面的例子一样,创建了两个ThreadDomain13对象,就产生了2个锁。既然两个线程持有的是不同的锁,自然不会受到"等待释放锁"这一行为的制约,可以分别运行addNum(String userName)中的代码。
synchronized(this)锁住的是什么?
锁住的是当前的对象。当synchronized块里的内容执行完之后,释放当前对象的锁。同一时刻若有多个线程访问这个对象,则会被阻塞。
synchronized(object)锁住的什么?
锁住的是object对象。当synchronized块里的内容执行完之后,释放object对象的锁。同一时刻若有多个线程访问这个对象,则会被阻塞。
这里需要注意的是如果object为Integer、String等等包装类时(new出的对象除外),并不会锁住当前对象,也不会阻塞线程。因为包装类是final的,不可修改的,如果修改则会生成一个新的对象。所以,在一个线程对其进行修改后,其他线程在获取该对象的锁时,该对象已经不是原来的那个对象,所以获取到的是另一个对象的锁,所以不会产生阻塞。
到此,相信大家对“Java并发synchronized用在方法上锁住的内容是什么”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流