对象及变量的并发访问——Synchronized详解
2016-09-27 20:41
429 查看
1:为什么需要同步
多个线程同时访问一个对象中的实例变量进行并发访问的时候会产生“非线程安全”的情况,产生的后果就是“脏读”,也就是取到的数据其实是被更改的;而“线程安全”就是以获得的实例变量的值进行同步处理的,不会出现脏读现象。2:synchronized 同步方法
脏读问题存在于“实例变量”中,如果是方法内部私有变量则不会出现脏读情况。2.1:方法内部私有变量为线程安全
public class t19 { public static void main(String[] args) { HasSelfPrivateNum numRef = new HasSelfPrivateNum(); ThreadA athread = new ThreadA(numRef); athread.start(); ThreadB bthread = new ThreadB(numRef); bthread.start(); } } class HasSelfPrivateNum { public void addI(String username) { try { int num = 0; if (username.equals("a")) { 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(); } } } class ThreadA extends Thread { private HasSelfPrivateNum numRef; public ThreadA(HasSelfPrivateNum numRef){ this.numRef = numRef; } public void run(){ numRef.addI("a"); } } class ThreadB extends Thread { private HasSelfPrivateNum numRef; public ThreadB(HasSelfPrivateNum numRef){ this.numRef = numRef; } public void run(){ numRef.addI("b"); } }
由上可见,方法变量中不存在费线程安全问题,永远都是线程安全的。这是方法内部私有变量造成的!!!
2.2:实例变量非线程安全
如果多个变量访问同一个对象中的实例变量,则有可能出现费线程安全的问题。public class t20 { public static void main(String[] args) { HasSelfPrivateNum1 numRef = new HasSelfPrivateNum1(); ThreadA1 athread = new ThreadA1(numRef); athread.start(); ThreadB1 bthread = new ThreadB1(numRef); bthread.start(); } } class HasSelfPrivateNum1 { private int num = 0; public void addI(String username) { try { if (username.equals("a")) { 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(); } } } class ThreadA1 extends Thread { private HasSelfPrivateNum1 numRef; public ThreadA1(HasSelfPrivateNum1 numRef){ this.numRef = numRef; } public void run(){ numRef.addI("a"); } } class ThreadB1 extends Thread { private HasSelfPrivateNum1 numRef; public ThreadB1(HasSelfPrivateNum1 numRef){ this.numRef = numRef; } public void run(){ numRef.addI("b"); } }
总结:在多个线程访问同一个对象中的同步方法时,一定是线程安全的;方法内部私有变量线程安全;类中实例变量线程不安全
2.3:多个对象多个锁
public class t21 { public static void main(String[] args) { HasSelfPrivateNum2 numRef1 = new HasSelfPrivateNum2(); HasSelfPrivateNum2 numRef2 = new HasSelfPrivateNum2(); ThreadA2 athread = new ThreadA2(numRef1); athread.start(); ThreadB2 bthread = new ThreadB2(numRef2); bthread.start(); } } class HasSelfPrivateNum2 { private int num = 0; synchronized public void addI(String username) { try { if (username.equals("a")) { 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(); } } } class ThreadA2 extends Thread { private HasSelfPrivateNum2 numRef; public ThreadA2(HasSelfPrivateNum2 numRef1){ this.numRef = numRef1; } public void run(){ numRef.addI("a"); } } class ThreadB2 extends Thread { private HasSelfPrivateNum2 numRef; public ThreadB2(HasSelfPrivateNum2 numRef2){ this.numRef = numRef2; } public void run(){ numRef.addI("b"); } }
上面示例中是两个线程分别访问同一个类的两个不同实例的相同名称的同步方法,效果缺失以异步的方式运行的。这是因为示例中创建了两个业务对象,在业务中产生了两个锁,所以会产生异步的效果。
虽然示例中使用了 synchronized 关键字,但是打印的顺序去不是同步的,视交叉的,为什么是这样呢?
关键字 synchronized 取得的锁都是对象锁,而不是把一段代码或方法当做锁。所以在上面的示例中,哪个线程先执行带 synchronized 关键字的方法,哪个线程就持有该方法所属对象的 lock 锁,那么其他线程只能能呈等待状态,前提是多个线程访问同一个对象。
多个线程访问多个对象,则 JVM 会创建多个锁。所以上面示例中产生了两个锁,所以产生了异步。
synchronized 方法与锁对象
相关文章推荐
- Codeforces Round #373 (Div. 2) E. Sasha and Array
- 正则表达式(Regular Expression,regex,regexp)
- 使用和配置RxBus
- Linux - C进程间通信(预习内容十)
- Qt Creator增强套装16.9.27.12更新
- [BZOJ1509][NOI2003]逃学的小孩(树形dp||dfs)
- Struts2基本使用(一)--在项目中引入Struts2
- Bootstrap入门(二十八)JS插件5:工具提醒
- Linux下getopt()函数的简单使用
- 完美者右键扩展菜单管理器 1.2.1 中文绿色版
- Pseudoprime numbers(poj3641)快速幂
- 大数据道场(HDP SandBox) 初探
- Android开启子线程
- iOS10-配置获取隐私数据权限声明
- rtems初始化过程分析
- 微信小应用的认识
- 拾取模型的原理及其在THREE.JS中的代码实现
- myeclipse 怎么安装SVN插件
- 获取Storm集群上TridentWordCount计算结果的方法
- 编写saltstack 扩展模块