多线程与并发 - 多线程访问同步方法的7种情况
2021/9/15 6:06:38
本文主要是介绍多线程与并发 - 多线程访问同步方法的7种情况,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
不啰嗦,我们直接开始!
1、两个线程同时访问一个对象的同步方法
代码:
public class SynchronizedObjectMethod implements Runnable { static SynchronizedObjectMethod instance = new SynchronizedObjectMethod(); @Override public void run() { method(); } public synchronized void method() { System.out.println("对象锁的方法修饰符形式,我叫:" + Thread.currentThread().getName()); try { System.out.println(Thread.currentThread().getName() + " 休眠3秒"); Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } public static void main(String[] args) { //两个线程访问一个对象的同步方法,对象为instance实例 Thread t1 = new Thread(instance); Thread t2 = new Thread(instance); t1.start(); t2.start(); while (t1.isAlive() || t2.isAlive()) { } System.out.println("fininshed"); } }
运行结果:
对象锁的方法修饰符形式,我叫:Thread-0 Thread-0 休眠3秒 Thread-0运行结束 对象锁的方法修饰符形式,我叫:Thread-1 Thread-1 休眠3秒 Thread-1运行结束 fininshed
解析:需要争抢同一把锁this,所以顺序执行。
2、两个线程访问的是两个对象的同步方法
代码:
public class SynchronizedTwoThreadToTwoObject implements Runnable { static SynchronizedTwoThreadToTwoObject instance1 = new SynchronizedTwoThreadToTwoObject(); static SynchronizedTwoThreadToTwoObject instance2 = new SynchronizedTwoThreadToTwoObject(); @Override public void run() { // 当前对象作为锁 synchronized (this) { System.out.println("我是对象锁的代码块形式,我叫" + Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } } public static void main(String[] args) { //两个线程访问的是两个对象的同步方法,两个对象一个为instance1,另一个为instance2 Thread t1 = new Thread(instance1); Thread t2 = new Thread(instance2); t1.start(); t2.start(); while (t1.isAlive() || t2.isAlive()) { } System.out.println("fininshed"); } }
运行结果:
我是对象锁的代码块形式,我叫Thread-0 我是对象锁的代码块形式,我叫Thread-1 Thread-1运行结束 Thread-0运行结束 fininshed
解析:并行处理,不受干扰,锁的实例不是同一个。
3、两个线程访问的是Synchronized的静态方法
代码:
public class SynchronizedClassStatic implements Runnable { static SynchronizedClassStatic instance1=new SynchronizedClassStatic(); static SynchronizedClassStatic instance2=new SynchronizedClassStatic(); @Override public void run() { method(); } public static synchronized void method(){ System.out.println("我是类锁的一种形式,我叫"+Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"线程结束"); } public static void main(String[] args){ //两个线程访问synchronized的静态方法 Thread t1=new Thread(instance1); Thread t2=new Thread(instance2); t1.start(); t2.start(); while (t1.isAlive()||t2.isAlive()){ } System.out.println("fininshed"); } }
运行结果:
我是类锁的一种形式,我叫Thread-0 Thread-0线程结束 我是类锁的一种形式,我叫Thread-1 Thread-1线程结束 fininshed
解析:对应的锁是同一把,一个一个的顺序执行。
4、同时访问同步方法与非同步方法
代码:
public class SynchronizedYesOrNo implements Runnable { static SynchronizedYesOrNo instance=new SynchronizedYesOrNo(); public static void main(String[] args) { Thread th1=new Thread(instance); Thread th2=new Thread(instance); th1.start(); th2.start(); while(th1.isAlive()||th2.isAlive()){ } System.out.println("finished"); } @Override public void run() { if(Thread.currentThread().getName().equals("Thread-0")){ method1(); }else{ method2(); } } public synchronized void method1(){ System.out.println("我是加了同步的方法"+Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"结束"); } public synchronized static void method2(){ System.out.println("我是没加了同步的方法"+Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"结束"); } }
运行结果:
我是加了同步的方法Thread-0 我是没加了同步的方法Thread-1 Thread-0结束 Thread-1结束 finished
解析:同步方法不会出现并发问题,非同步方法不会受到影响,出现并发问题。
5、访问同一个对象的不同的普通同步方法
代码:
public class SynchronizedDifferentMethod implements Runnable { static SynchronizedDifferentMethod instance=new SynchronizedDifferentMethod(); @Override public void run() { if(Thread.currentThread().getName().equals("Thread-0")){ method1(); }else { method2(); } } public synchronized void method1(){ System.out.println("我是加锁的方法"+Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"线程执行结束"); } public synchronized void method2(){ System.out.println("我也是加锁的方法"+Thread.currentThread().getName()+"线程执行结束"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"线程执行结束"); } public static void main(String[] args) throws InterruptedException{ Thread t1=new Thread(instance); Thread t2=new Thread(instance); t1.start(); t2.start(); while (t1.isAlive()||t2.isAlive()){} System.out.println("fininshed"); } }
运行结果:
我是加锁的方法Thread-0 Thread-0线程执行结束 我也是加锁的方法Thread-1线程执行结束 Thread-1线程执行结束 fininshed
解析:拿到的是this锁,所以还是会受影响,串行执行。
6、同时访问静态synchronized和非静态synchronized
代码:
public class SynchronizedStaticAndNormal implements Runnable { static SynchronizedStaticAndNormal instance=new SynchronizedStaticAndNormal(); @Override public void run() { if(Thread.currentThread().getName().equals("Thread-0")){ method1(); }else { method2(); } } public synchronized static void method1(){ System.out.println("我是加锁的静态方法1 "+Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"线程执行结束"); } public synchronized void method2(){ System.out.println("我是加锁的非静态方法2 "+Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"线程执行结束"); } public static void main(String[] args) throws InterruptedException{ Thread t1=new Thread(instance); Thread t2=new Thread(instance); t1.start(); t2.start(); while (t1.isAlive()||t2.isAlive()){} System.out.println("fininshed"); } }
运行结果:
我是加锁的静态方法1 Thread-0 我是加锁的非静态方法2 Thread-1 Thread-1线程执行结束 Thread-0线程执行结束 fininshed
解析:method1锁的是.class对象,method2锁的是this对象,锁不一样,没有冲突,并行执行。
7、方法抛异常后,会释放锁
代码:
public class SynchronizedException implements Runnable { static SynchronizedException instance = new SynchronizedException(); @Override public void run() { if (Thread.currentThread().getName().equals("Thread-0")) { method1(); } else { method2(); } } public synchronized void method1() { /* // 抛出Exception System.out.println("我是加锁的静态方法1" + Thread.currentThread().getName()); try { Thread.sleep(3000); //异常抛出后,JVM会自动帮你释放锁,不需要自己手动释放锁。 throw new Exception(); } catch (InterruptedException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "线程执行结束"); */ // 抛出RuntimeException System.out.println("我是加锁的静态方法1" + Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } //异常抛出后,JVM会自动帮你释放锁,不需要自己手动释放锁。 throw new RuntimeException(); // System.out.println(Thread.currentThread().getName() + "线程执行结束"); } public synchronized void method2() { System.out.println("我也是加锁的非静态方法2" + Thread.currentThread().getName()); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "线程执行结束"); } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(instance); Thread t2 = new Thread(instance); t1.start(); t2.start(); while (t1.isAlive() || t2.isAlive()) { } System.out.println("fininshed"); } }
运行结果:
我是加锁的静态方法1Thread-0 Exception in thread "Thread-0" java.lang.RuntimeException at com.interview.javabasic.thread.a0914.SynchronizedException.method1(SynchronizedException.java:50) at com.interview.javabasic.thread.a0914.SynchronizedException.run(SynchronizedException.java:16) at java.lang.Thread.run(Thread.java:748) 我也是加锁的非静态方法2Thread-1 Thread-1线程执行结束 fininshed
解析:方法抛出异常后,会释放锁。
总结:
- 一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待(对应第1、5种情况)
- 每一个实例都对应有自己的一把锁,不同实例之间互不影响;例外:锁对象是 *.class 以及synchronized修饰的是static方法的时候,所有对象公用一把类锁(对应第2、3、4、6种情况)
- 无论方法正常执行完毕或者方法抛出异常,都会释放锁(对应第7种情况)。
- 目前进入被synchronized 的方法,在这方法里面调用没有synchronized修饰的方法。还是线程安全的吗?(不是线程安全的,出了synchronized,进入没有被synchronized修饰的方法,就可以同时被多个线程调用。)
参考文章:
- (Synchronized)多线程访问同步方法的七种具体情况
- Java 多线程访问同步方法的七种情况
不啰嗦,文章结束,建议三连!
这篇关于多线程与并发 - 多线程访问同步方法的7种情况的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-28MQ底层原理资料详解:新手入门教程
- 2024-11-28MQ项目开发资料详解:新手入门教程
- 2024-11-28MQ项目开发资料详解:入门与初级用户指南
- 2024-11-28MQ消息队列资料入门教程
- 2024-11-28MQ消息队列资料:新手入门详解
- 2024-11-28MQ消息中间件资料详解与应用教程
- 2024-11-28MQ消息中间件资料入门教程
- 2024-11-28MQ源码资料详解与入门教程
- 2024-11-28MQ源码资料入门教程
- 2024-11-28RocketMQ底层原理资料详解