当前位置:   article > 正文

多线程与并发 - 多线程访问同步方法的7种情况

多线程与并发 - 多线程访问同步方法的7种情况

不啰嗦,我们直接开始!

1、两个线程同时访问一个对象的同步方法

代码:

  1. public class SynchronizedObjectMethod implements Runnable {
  2. static SynchronizedObjectMethod instance = new SynchronizedObjectMethod();
  3. @Override
  4. public void run() {
  5. method();
  6. }
  7. public synchronized void method() {
  8. System.out.println("对象锁的方法修饰符形式,我叫:" + Thread.currentThread().getName());
  9. try {
  10. System.out.println(Thread.currentThread().getName() + " 休眠3秒");
  11. Thread.sleep(3000);
  12. } catch (InterruptedException e) {
  13. e.printStackTrace();
  14. }
  15. System.out.println(Thread.currentThread().getName() + "运行结束");
  16. }
  17. public static void main(String[] args) {
  18. //两个线程访问一个对象的同步方法,对象为instance实例
  19. Thread t1 = new Thread(instance);
  20. Thread t2 = new Thread(instance);
  21. t1.start();
  22. t2.start();
  23. while (t1.isAlive() || t2.isAlive()) {
  24. }
  25. System.out.println("fininshed");
  26. }
  27. }

运行结果:

  1. 对象锁的方法修饰符形式,我叫:Thread-0
  2. Thread-0 休眠3
  3. Thread-0运行结束
  4. 对象锁的方法修饰符形式,我叫:Thread-1
  5. Thread-1 休眠3
  6. Thread-1运行结束
  7. fininshed

解析:需要争抢同一把锁this,所以顺序执行。

2、两个线程访问的是两个对象的同步方法

代码:

  1. public class SynchronizedTwoThreadToTwoObject implements Runnable {
  2. static SynchronizedTwoThreadToTwoObject instance1 = new SynchronizedTwoThreadToTwoObject();
  3. static SynchronizedTwoThreadToTwoObject instance2 = new SynchronizedTwoThreadToTwoObject();
  4. @Override
  5. public void run() {
  6. // 当前对象作为锁
  7. synchronized (this) {
  8. System.out.println("我是对象锁的代码块形式,我叫" + Thread.currentThread().getName());
  9. try {
  10. Thread.sleep(3000);
  11. } catch (InterruptedException e) {
  12. e.printStackTrace();
  13. }
  14. System.out.println(Thread.currentThread().getName() + "运行结束");
  15. }
  16. }
  17. public static void main(String[] args) {
  18. //两个线程访问的是两个对象的同步方法,两个对象一个为instance1,另一个为instance2
  19. Thread t1 = new Thread(instance1);
  20. Thread t2 = new Thread(instance2);
  21. t1.start();
  22. t2.start();
  23. while (t1.isAlive() || t2.isAlive()) {
  24. }
  25. System.out.println("fininshed");
  26. }
  27. }

运行结果:

  1. 我是对象锁的代码块形式,我叫Thread-0
  2. 我是对象锁的代码块形式,我叫Thread-1
  3. Thread-1运行结束
  4. Thread-0运行结束
  5. fininshed

解析:并行处理,不受干扰,锁的实例不是同一个。

3、两个线程访问的是Synchronized的静态方法

代码:

  1. public class SynchronizedClassStatic implements Runnable {
  2. static SynchronizedClassStatic instance1=new SynchronizedClassStatic();
  3. static SynchronizedClassStatic instance2=new SynchronizedClassStatic();
  4. @Override
  5. public void run() {
  6. method();
  7. }
  8. public static synchronized void method(){
  9. System.out.println("我是类锁的一种形式,我叫"+Thread.currentThread().getName());
  10. try {
  11. Thread.sleep(3000);
  12. } catch (InterruptedException e) {
  13. e.printStackTrace();
  14. }
  15. System.out.println(Thread.currentThread().getName()+"线程结束");
  16. }
  17. public static void main(String[] args){
  18. //两个线程访问synchronized的静态方法
  19. Thread t1=new Thread(instance1);
  20. Thread t2=new Thread(instance2);
  21. t1.start();
  22. t2.start();
  23. while (t1.isAlive()||t2.isAlive()){
  24. }
  25. System.out.println("fininshed");
  26. }
  27. }

运行结果:

  1. 我是类锁的一种形式,我叫Thread-0
  2. Thread-0线程结束
  3. 我是类锁的一种形式,我叫Thread-1
  4. Thread-1线程结束
  5. fininshed

解析:对应的锁是同一把,一个一个的顺序执行。

4、同时访问同步方法与非同步方法

代码:

  1. public class SynchronizedYesOrNo implements Runnable {
  2. static SynchronizedYesOrNo instance=new SynchronizedYesOrNo();
  3. public static void main(String[] args) {
  4. Thread th1=new Thread(instance);
  5. Thread th2=new Thread(instance);
  6. th1.start();
  7. th2.start();
  8. while(th1.isAlive()||th2.isAlive()){
  9. }
  10. System.out.println("finished");
  11. }
  12. @Override
  13. public void run() {
  14. if(Thread.currentThread().getName().equals("Thread-0")){
  15. method1();
  16. }else{
  17. method2();
  18. }
  19. }
  20. public synchronized void method1(){
  21. System.out.println("我是加了同步的方法"+Thread.currentThread().getName());
  22. try {
  23. Thread.sleep(3000);
  24. } catch (InterruptedException e) {
  25. // TODO Auto-generated catch block
  26. e.printStackTrace();
  27. }
  28. System.out.println(Thread.currentThread().getName()+"结束");
  29. }
  30. public synchronized static void method2(){
  31. System.out.println("我是没加了同步的方法"+Thread.currentThread().getName());
  32. try {
  33. Thread.sleep(3000);
  34. } catch (InterruptedException e) {
  35. // TODO Auto-generated catch block
  36. e.printStackTrace();
  37. }
  38. System.out.println(Thread.currentThread().getName()+"结束");
  39. }
  40. }

运行结果:

  1. 我是加了同步的方法Thread-0
  2. 我是没加了同步的方法Thread-1
  3. Thread-0结束
  4. Thread-1结束
  5. finished

解析:同步方法不会出现并发问题,非同步方法不会受到影响,出现并发问题。

5、访问同一个对象的不同的普通同步方法

代码:

  1. public class SynchronizedDifferentMethod implements Runnable {
  2. static SynchronizedDifferentMethod instance=new SynchronizedDifferentMethod();
  3. @Override
  4. public void run() {
  5. if(Thread.currentThread().getName().equals("Thread-0")){
  6. method1();
  7. }else {
  8. method2();
  9. }
  10. }
  11. public synchronized void method1(){
  12. System.out.println("我是加锁的方法"+Thread.currentThread().getName());
  13. try {
  14. Thread.sleep(3000);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. System.out.println(Thread.currentThread().getName()+"线程执行结束");
  19. }
  20. public synchronized void method2(){
  21. System.out.println("我也是加锁的方法"+Thread.currentThread().getName()+"线程执行结束");
  22. try {
  23. Thread.sleep(3000);
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. }
  27. System.out.println(Thread.currentThread().getName()+"线程执行结束");
  28. }
  29. public static void main(String[] args) throws InterruptedException{
  30. Thread t1=new Thread(instance);
  31. Thread t2=new Thread(instance);
  32. t1.start();
  33. t2.start();
  34. while (t1.isAlive()||t2.isAlive()){}
  35. System.out.println("fininshed");
  36. }
  37. }

运行结果:

  1. 我是加锁的方法Thread-0
  2. Thread-0线程执行结束
  3. 我也是加锁的方法Thread-1线程执行结束
  4. Thread-1线程执行结束
  5. fininshed

解析:拿到的是this锁,所以还是会受影响,串行执行。

6、同时访问静态synchronized和非静态synchronized

代码:

  1. public class SynchronizedStaticAndNormal implements Runnable {
  2. static SynchronizedStaticAndNormal instance=new SynchronizedStaticAndNormal();
  3. @Override
  4. public void run() {
  5. if(Thread.currentThread().getName().equals("Thread-0")){
  6. method1();
  7. }else {
  8. method2();
  9. }
  10. }
  11. public synchronized static void method1(){
  12. System.out.println("我是加锁的静态方法1 "+Thread.currentThread().getName());
  13. try {
  14. Thread.sleep(3000);
  15. } catch (InterruptedException e) {
  16. e.printStackTrace();
  17. }
  18. System.out.println(Thread.currentThread().getName()+"线程执行结束");
  19. }
  20. public synchronized void method2(){
  21. System.out.println("我是加锁的非静态方法2 "+Thread.currentThread().getName());
  22. try {
  23. Thread.sleep(3000);
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. }
  27. System.out.println(Thread.currentThread().getName()+"线程执行结束");
  28. }
  29. public static void main(String[] args) throws InterruptedException{
  30. Thread t1=new Thread(instance);
  31. Thread t2=new Thread(instance);
  32. t1.start();
  33. t2.start();
  34. while (t1.isAlive()||t2.isAlive()){}
  35. System.out.println("fininshed");
  36. }
  37. }

运行结果:

  1. 我是加锁的静态方法1 Thread-0
  2. 我是加锁的非静态方法2 Thread-1
  3. Thread-1线程执行结束
  4. Thread-0线程执行结束
  5. fininshed

解析:method1锁的是.class对象,method2锁的是this对象,锁不一样,没有冲突,并行执行。

7、方法抛异常后,会释放锁

代码:

  1. public class SynchronizedException implements Runnable {
  2. static SynchronizedException instance = new SynchronizedException();
  3. @Override
  4. public void run() {
  5. if (Thread.currentThread().getName().equals("Thread-0")) {
  6. method1();
  7. } else {
  8. method2();
  9. }
  10. }
  11. public synchronized void method1() {
  12. /*
  13. // 抛出Exception
  14. System.out.println("我是加锁的静态方法1" + Thread.currentThread().getName());
  15. try {
  16. Thread.sleep(3000);
  17. //异常抛出后,JVM会自动帮你释放锁,不需要自己手动释放锁。
  18. throw new Exception();
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. } catch (Exception e) {
  22. e.printStackTrace();
  23. }
  24. System.out.println(Thread.currentThread().getName() + "线程执行结束");
  25. */
  26. // 抛出RuntimeException
  27. System.out.println("我是加锁的静态方法1" + Thread.currentThread().getName());
  28. try {
  29. Thread.sleep(3000);
  30. } catch (InterruptedException e) {
  31. e.printStackTrace();
  32. } catch (Exception e) {
  33. e.printStackTrace();
  34. }
  35. //异常抛出后,JVM会自动帮你释放锁,不需要自己手动释放锁。
  36. throw new RuntimeException();
  37. // System.out.println(Thread.currentThread().getName() + "线程执行结束");
  38. }
  39. public synchronized void method2() {
  40. System.out.println("我也是加锁的非静态方法2" + Thread.currentThread().getName());
  41. try {
  42. Thread.sleep(3000);
  43. } catch (InterruptedException e) {
  44. e.printStackTrace();
  45. }
  46. System.out.println(Thread.currentThread().getName() + "线程执行结束");
  47. }
  48. public static void main(String[] args) throws InterruptedException {
  49. Thread t1 = new Thread(instance);
  50. Thread t2 = new Thread(instance);
  51. t1.start();
  52. t2.start();
  53. while (t1.isAlive() || t2.isAlive()) {
  54. }
  55. System.out.println("fininshed");
  56. }
  57. }

运行结果:

  1. 我是加锁的静态方法1Thread-0
  2. Exception in thread "Thread-0" java.lang.RuntimeException
  3. at com.interview.javabasic.thread.a0914.SynchronizedException.method1(SynchronizedException.java:50)
  4. at com.interview.javabasic.thread.a0914.SynchronizedException.run(SynchronizedException.java:16)
  5. at java.lang.Thread.run(Thread.java:748)
  6. 我也是加锁的非静态方法2Thread-1
  7. Thread-1线程执行结束
  8. fininshed

解析:方法抛出异常后,会释放锁。

总结:

  1. 一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待(对应第1、5种情况)
  2. 每一个实例都对应有自己的一把锁,不同实例之间互不影响;例外:锁对象是 *.class 以及synchronized修饰的是static方法的时候,所有对象公用一把类锁(对应第2、3、4、6种情况)
  3. 无论方法正常执行完毕或者方法抛出异常,都会释放锁(对应第7种情况)。
  4. 目前进入被synchronized 的方法,在这方法里面调用没有synchronized修饰的方法。还是线程安全的吗?(不是线程安全的,出了synchronized,进入没有被synchronized修饰的方法,就可以同时被多个线程调用。)

参考文章:

不啰嗦,文章结束,期待三连!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/330269
推荐阅读
相关标签
  

闽ICP备14008679号