当前位置:   article > 正文

java中synchronized的三种写法详解_synchronize写法

synchronize写法

预备知识

首先,我们得知道在java中存在三种变量:

  1. 实例变量 ==》 存在于堆中
  2. 静态变量 ==》 存在于方法区中
  3. 局部变量 ==》 存在于栈中

然后,我们得明白,合适会发生高并发不安全

  • 条件1:多线程并发。
  • 条件2:有共享数据。
  • 条件3:共享数据有修改的行为。

具体不安全案例请参考 如下这篇文章:java线程安全问题详解_我想月薪过万的博客-CSDN博客icon-default.png?t=LA92https://blog.csdn.net/qq_41885673/article/details/121431714

在上面这篇文章银行取钱案例中,我们解决线程安全问题的方法是加了一个 synchronized 关键字。下面我们就详细介绍一下 synchronized 的三种写法,分别解决什么问题!!!

写法一:修饰代码块

  1. package ThreadSafa;
  2. public class Test {
  3. public static void main(String[] args) {
  4. TestAccount ta1 = new TestAccount();
  5. ta1.setNum(10);
  6. //共用一个账户对象
  7. TestThread t1 = new TestThread(ta1);
  8. TestThread t2 = new TestThread(ta1);
  9. t1.start();
  10. t2.start();
  11. }
  12. }
  13. class TestThread extends Thread {
  14. private TestAccount mAccount;
  15. public TestThread(TestAccount mAccount) {
  16. this.mAccount = mAccount;
  17. }
  18. @Override
  19. public void run() {
  20. mAccount.updateNum(1);
  21. }
  22. }
  23. class TestAccount {
  24. private double num;
  25. public double getNum() {
  26. return num;
  27. }
  28. public void setNum(double num) {
  29. this.num = num;
  30. }
  31. public void updateNum(int n) {
  32. synchronized (this) {
  33. try {
  34. Thread.sleep(1000);
  35. } catch (InterruptedException e) {
  36. e.printStackTrace();
  37. }
  38. setNum(getNum() - n);
  39. }
  40. System.out.println(getNum());
  41. }
  42. }

运行结果

 写法二:修饰方法

  1. package ThreadSafa;
  2. public class Test {
  3. public static void main(String[] args) {
  4. TestAccount ta1 = new TestAccount();
  5. ta1.setNum(10);
  6. TestThread t1 = new TestThread(ta1);
  7. TestThread t2 = new TestThread(ta1);
  8. t1.start();
  9. t2.start();
  10. }
  11. }
  12. class TestThread extends Thread {
  13. private TestAccount mAccount;
  14. public TestThread(TestAccount mAccount) {
  15. this.mAccount = mAccount;
  16. }
  17. @Override
  18. public void run() {
  19. mAccount.updateNum(1);
  20. }
  21. }
  22. class TestAccount {
  23. private double num;
  24. public double getNum() {
  25. return num;
  26. }
  27. public void setNum(double num) {
  28. this.num = num;
  29. }
  30. public synchronized void updateNum(int n) {
  31. try {
  32. Thread.sleep(1000);
  33. } catch (InterruptedException e) {
  34. e.printStackTrace();
  35. }
  36. setNum(getNum() - n);
  37. System.out.println(getNum());
  38. }
  39. }

运行结果

总结

可以看到 ,前面这两种写法其实是等价的,什么意思呢?就是当你用 synchronized 修饰共享对象 this 的时候 你就可以吧 synchronized 提到方法前面,但是我们一般不会这么干,因为扩大 synchronized 修饰的代码范围会使代码运行效率降低。

同时,前面两种方法都是为了解决 实例变量 线程安全问题而诞生的,对于静态变量我们怎么处理呢?请看写法三:

写法三:修饰静态方法

  1. package ThreadSafa;
  2. public class Test {
  3. public static void main(String[] args) {
  4. TestAccount ta1 = new TestAccount();
  5. TestAccount ta2 = new TestAccount();
  6. TestThread t1 = new TestThread(ta1);
  7. TestThread t2 = new TestThread(ta2);
  8. t1.start();
  9. t2.start();
  10. }
  11. }
  12. class TestThread extends Thread {
  13. private TestAccount mAccount;
  14. public TestThread(TestAccount mAccount) {
  15. this.mAccount = mAccount;
  16. }
  17. @Override
  18. public void run() {
  19. mAccount.updateCount(1);
  20. }
  21. }
  22. class TestAccount {
  23. private double num;
  24. public static double count = 10;
  25. public double getNum() {
  26. return num;
  27. }
  28. public void setNum(double num) {
  29. this.num = num;
  30. }
  31. public synchronized void updateNum(int n) {
  32. try {
  33. Thread.sleep(1000);
  34. } catch (InterruptedException e) {
  35. e.printStackTrace();
  36. }
  37. setNum(getNum() - n);
  38. System.out.println(getNum());
  39. }
  40. public synchronized static void updateCount(int n) {
  41. try {
  42. Thread.sleep(1000);
  43. } catch (InterruptedException e) {
  44. e.printStackTrace();
  45. }
  46. count -= n;
  47. System.out.println(count);
  48. }
  49. }

运行结果展示

可以看到,在静态方法上加 synchronized 之后,他锁的是这个类,尽管两个账户对象不一样,但是,加了 synchronized 会保证他们排队执行,也就是保证了线程安全。

总结

局部变量 =》 存在于栈中 =》 线程之间不能共享 =》 所以数据永远是安全的

实例变量 =》 存在于堆中 =》 线程之间能共享 =》 采用写法一和写法二保证线程安全

静态变量 =》 存在于方法区 =》 线程之间能共享 =》 采用方写法三保证线程安全

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号