Java synchronized关键字
来源:互联网 发布:淘宝分销是什么意思 编辑:程序博客网 时间:2024/06/06 00:33
文章目录 一、“脏数据”的产生 1、银行存钱的例子 2、原因 当多条语句在操作线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程参与进来。导致共享数据的错误。 3、解决方案 对多条操作共享数据的语句,只能让一个线程执行完。再执行过程中,其他线程不能够参与执行。 二、同步方案 1、同步代码块 2、同步方法 3、锁 在使用同步代码块方法时, 非静态方法可以使用 this 或者 Class 对象(字节码文件对象) 静态方法必须使用Class对象(字节码文件对象)来同步三、使用snchroized关键字注意的点 1、snchroized 关键字不能被继承 2、在接口定义方法时不能使用snchroized 关键字 3、构造方法不能使用 snchroized 关键字,但是可以使用同步代码块来进行同步 4、可以自由放置 snchroized 5、大量使用 snchroized 会造成 不必要的资源消耗和性能损失四、如何排查线程安全问题1、明确哪些代码是多线程运行的代码2、明确共享数据3、明确多线程运行代码哪些语句是操作共享数据五、利用同步 解决线程安全问题的 前提1、必须要>=2 个线程2、必须是多个线程使用同一个锁六、利弊1、优点: 解决了多线程安全问题2、当线程获取到执行权的时候,每次都判断锁,消耗了资源(这个资源是在允许范围内的)扩展 : 如何保证单例
一、脏数据的产生
1、银行存钱的例子
两个储户分别同时往银行存300元,每次存100,分三次存。
代码如下 :
//银行public class Bank { private int sum = 0; public void add(int n ) { sum += n; System.out.println(sum); }}//用户 public class User implements Runnable{ private Bank bank = new Bank(); @Override public void run() { for(int x= 0 ; x < 3;x++) { bank.add(100); } }}// 在main 函数中 public static void main(String[] args) { //线程对象a User a = new User(); Thread t1 = new Thread(a); //线程对象b User b = new User(); Thread t2 = new Thread(b); t1.start(); t2.start(); }
// 可能的输出结果200200400400600600
2、原因
两个线程同时访问共享数据 sum 。当第一条线 t1 程执行到 sum,并对sum进行数据操作时候,t1线程还未执行输出语句时候,失去执行权。t2线程对象获取执行权去执行sum数据操操作。同样的,还未执行到输出语句时候,t2 失去执行权。此刻t1 获取到执行权,执行输出语句。执行完成后,t1失去执行权,t2 获取到执行权,也同样执行输出语句。以此类推…
总结为:当多条语句在操作线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程参与进来。导致共享数据的错误。
如何模拟出现上述结果,其实也很简单,sleep()下即可。修改如下
public class Bank { private int sum = 0; public void add(int n ) { sum += n; try { Thread.sleep(10); }catch (InterruptedException e) { } System.out.println(sum); }}
注意: 上述的 add方法是可以throws 异常,在run方法里面进行try-catch。 但是,run 方法不能throws 异常的。
3、解决方案
对多条操作共享数据的语句,只能让一个线程执行完。再执行过程中,其他线程不能够参与执行。
Java 对于多线程的安全问题提供了专业的解决方式。
二、同步方案
1、同步代码块
synchronized (对象) { //需要被同步的代码} //注意: 对象如同锁。持有锁的线程可以在同步中执行。没有持有锁的线程即使获取到执行权,也进不去。
对add方法修改如下:
public class Bank { private int sum = 0; Object obj = new Object(); public void add(int n ) { // 同步代码块 synchronized (obj) { sum += n; try { Thread.sleep(10); }catch (InterruptedException e) { } System.out.println(sum); } }}
2、同步方法
在函数方法名前添加 synchronized 关键字 。
那么同步函数是哪一个锁呢 ? 函数需要被对象调用,那么函数都持有对象引用,就是this.所以同步函数使用的锁是 this。
如果同步函数被静态修饰后,使用的锁是什么 ? 该方法所在类的字节码文件对象,即 Class 对象。如何获取 ? 类名.class 或者 实例对象.getClass()
注意 : 非静态函数 同步的锁 可以是当前对象,也可以是非静态函数所在类的字节码文件对象。
修改如下:
public class Bank { private int sum = 0; //Object obj = new Object(); public synchronized void add(int n ) { //synchronized (obj) //{ sum += n; try { Thread.sleep(10); }catch (InterruptedException e) { } System.out.println(sum); } //}}
三、使用snchroized关键字注意的点
1、snchroized 关键字不能被继承
如果在父类某个方法使用 snchroized 关键字,而自类覆盖了,子类默认情况是不同步的。如果子类方法也需要通保护,有两个方法,方法名前添加 snchroized 或者 在方法体内 调用父类方法。
2、在接口定义方法时不能使用snchroized 关键字
3、构造方法不能使用 snchroized 关键字,但是可以使用同步代码块来进行同步
4、可以自由放置 snchroized
snchroized 不能放在 方法返回值类型后面 !!!
5、大量使用 snchroized 会造成 不必要的资源消耗和性能损失
四、如何查找线程安全问题
1、明确哪些代码是多线程运行的代码 即 run方法2.、明确共享数据 sum3、明确多线程运行代码哪些语句是操作共享数据 sim += n 和 输出语句
五、利用同步解决线程安全问题的的前提
1、必须要>=2 个线程2、必须是多个线程使用同一个锁
六、同步的利弊如下
优点: 解决了多线程安全问题弊端:当线程获取到执行权的时候,每次都判断锁,消耗了资源(这个资源是在允许范围内的)
多线程在单例中的运用
- Java中的synchronized关键字
- java的synchronized关键字
- java中的synchronized关键字
- java中的synchronized关键字
- java中的synchronized关键字
- Java中的synchronized关键字
- Java synchronized关键字
- java中的synchronized关键字
- java synchronized关键字
- java synchronized 关键字
- Java的关键字synchronized
- java关键字synchronized
- java synchronized关键字理解
- Java中的synchronized关键字
- java中的synchronized关键字
- JAVA synchronized 关键字
- java中的synchronized关键字
- Java synchronized关键字详解
- 计算机网络-001-计算机网络在信息时代中的作用
- 初识依赖注入和Ioc容器
- leetcode_27. Remove Element ? 待解决
- 第九周 项目3 利用二叉树遍历思想解决问题
- 浅谈压缩感知(一):背景简介
- Java synchronized关键字
- 使用函数添加环境变量
- Wannafly挑战赛4——A-解方程(二分)
- PHP中,Json AJax传输数据
- 120. Triangle
- C++类模板 template <class T>详细使用方法
- Sobel函数原理和应用
- WebGoat小记
- git使用系列(一)