全部
技术
PHP
MySQL
前端
Linux
JAVA
工具
纪念日计算器
邮记星
个人记账
笔记侠
历史上的今天
生日密码
生日书
生日密码
生日花语
博古通今
三十六计
鬼谷子
笑林广记
本草纲目
山海经
唐诗宋词
宋词300首
唐诗300首
退出
登录
注册
编辑文章
选择分类
PHP
MySQL
前端
Linux
Java
工具
选择专栏
设计模式
java基础
Angular学习
Java面试题
描述:
封面图上传 :
+
点击上传图片
1. 两个线程同时访问一个对象的同步方法 这种情况,他们会一个一个执行 ``` package top.bowen.controller; public class SynchronizedObjectMethod implements Runnable { @Override public void run() { method(); } //方法加了synchronized关键字,如果不加,将会同时执行 public synchronized void method(){ System.out.println("我是对象锁的方法修饰符 "+ Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } public static void main(String[] args) { SynchronizedObjectMethod instance = new SynchronizedObjectMethod(); Thread t1 = new Thread(instance); Thread t2 = new Thread(instance); t1.start(); t2.start(); } } ``` 运行结果: ``` 我是对象锁的方法修饰符 Thread-0 Thread-0运行结束 我是对象锁的方法修饰符 Thread-1 Thread-1运行结束 ``` PS: **Void类是用final修饰的,说明不可以扩展,另外构造方法是私有的,不可以实例化; Void类是一个不可实例化的占位符类,用来保存一个引用代表了Java关键字void的Class对象。 public synchronized void method是同一个对象的void方法,那么他指代的是同一个类** 2. 两个线程访问两个对象的同步方法 两个线程会同时执行,因为他们相当于是两个不同的实例 ``` package top.bowen.controller; public class synchronizedCodeBlock implements Runnable { @Override public void run() { //使用的是this,但是是新建了两个不同的实例,所以不是同一个锁 synchronized (this){ System.out.println("我是对象锁的同步代码块 "+ Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } } public static void main(String[] args) { synchronizedCodeBlock instance1 = new synchronizedCodeBlock(); synchronizedCodeBlock instance2 = new synchronizedCodeBlock(); Thread t1 = new Thread(instance1); Thread t2 = new Thread(instance2); t1.start(); t2.start(); } } ``` 运行结果: ``` 我是对象锁的同步代码块 Thread-0 我是对象锁的同步代码块 Thread-1 Thread-1运行结束 Thread-0运行结束 ``` 3. 两个线程访问的是synchronized的静态方法 他们一个一个执行,不同的实例,但是方法是静态的,那么对应的锁就是同一把,所以他们会一个一个执行 ``` package top.bowen.controller; public class synchronizedStaticMethod implements Runnable { @Override public void run() { method(); } public static synchronized void method(){ System.out.println("我是对象锁的静态方法 "+ Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } public static void main(String[] args) { synchronizedStaticMethod instance1 = new synchronizedStaticMethod(); synchronizedStaticMethod instance2 = new synchronizedStaticMethod(); Thread t1 = new Thread(instance1); Thread t2 = new Thread(instance2); t1.start(); t2.start(); } } ``` 运行结果: ``` 我是对象锁的静态方法 Thread-0 Thread-0运行结束 我是对象锁的静态方法 Thread-1 Thread-1运行结束 ``` 4. 同时访问同步方法和非同步方法 非同步方法不受到同步方法的影响, ``` package top.bowen.controller; /** * 多线程同时访问同步方法和非同步方法 */ public class SynchronizedYesOrNo implements Runnable{ @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(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } public void method2(){ System.out.println("我是不加锁的方法 "+ Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } public static void main(String[] args) { SynchronizedYesOrNo instance1 = new SynchronizedYesOrNo(); SynchronizedYesOrNo instance2 = new SynchronizedYesOrNo(); Thread t1 = new Thread(instance1); Thread t2 = new Thread(instance2); t1.start(); t2.start(); } } ``` 运行结果: ``` 我是不加锁的方法 Thread-1 我是加锁方法 Thread-0 Thread-0运行结束 Thread-1运行结束 ``` 5. 访问同一个对象不同的普通同步方法 同一个对象是一个实例,那么两个方法需要一个一个执行 ``` package top.bowen.controller; public class SynchronizedTwoMethod implements Runnable{ @Override public void run() { if(Thread.currentThread().getName().equals("Thread-0")){ method1(); }else{ method2(); } } public synchronized void method1(){ System.out.println("我是method1 "+ Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } public synchronized void method2(){ System.out.println("我是method2 "+ Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } public static void main(String[] args) { SynchronizedTwoMethod instance1 = new SynchronizedTwoMethod(); // SynchronizedTwoMethod instance2 = new SynchronizedTwoMethod(); Thread t1 = new Thread(instance1); Thread t2 = new Thread(instance1); t1.start(); t2.start(); } } ``` 运行结果: ``` 我是method1 Thread-0 Thread-0运行结束 我是method2 Thread-1 Thread-1运行结束 ``` 6. 静态方法锁和非静态方法锁 他们想当于是两把不同的锁,void method2()背后是this;static synchronized void method1背后是.class对象,他们两个对象不一样,所以会同步执行 ``` package top.bowen.controller; public class SynchronizedstaticAndNom implements Runnable{ @Override public void run() { if(Thread.currentThread().getName().equals("Thread-0")){ method1(); }else{ method2(); } } public static synchronized void method1(){ System.out.println("我是静态方法method1 "+ Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } public synchronized void method2(){ System.out.println("我是非静态方法method2 "+ Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } public static void main(String[] args) { SynchronizedstaticAndNom instance1 = new SynchronizedstaticAndNom(); // SynchronizedTwoMethod instance2 = new SynchronizedTwoMethod(); Thread t1 = new Thread(instance1); Thread t2 = new Thread(instance1); t1.start(); t2.start(); } } ``` 运行结果: ``` 我是非静态方法method2 Thread-1 我是静态方法method1 Thread-0 Thread-1运行结束 Thread-0运行结束 ``` 7.方法抛出异常后,会释放锁 抛出异常后,java会自动帮我们释放锁 ``` package top.bowen.controller; /** * 方法抛出异常时,锁是否会被释放 * 展示不抛出异常和抛出异常后 * 一旦抛出异常,第二个线程会立即进入同步方法,说明锁被释放了 * */ public class SynchronizedException implements Runnable { @Override public void run() { if(Thread.currentThread().getName().equals("Thread-0")){ method1(); }else{ method2(); } } public synchronized void method1(){ System.out.println("我是method1 "+ Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } //抛出异常 throw new RuntimeException(); } public synchronized void method2(){ System.out.println("我是method2 "+ Thread.currentThread().getName()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "运行结束"); } public static void main(String[] args) { SynchronizedException instance1 = new SynchronizedException(); // SynchronizedTwoMethod instance2 = new SynchronizedTwoMethod(); Thread t1 = new Thread(instance1); Thread t2 = new Thread(instance1); t1.start(); t2.start(); } } ``` 运行结果: ``` 我是method1 Thread-0 我是method2 Thread-1 Exception in thread "Thread-0" java.lang.RuntimeException at top.bowen.controller.SynchronizedException.method1(SynchronizedException.java:28) at top.bowen.controller.SynchronizedException.run(SynchronizedException.java:13) at java.base/java.lang.Thread.run(Thread.java:834) Thread-1运行结束 Process finished with exit code 0 ``` ### 总结 - 一把锁只能同时被一个线程获取,没有拿到锁的线程必须等待(对应1、5种情况) - 每个实例都对应有自己的一把锁,不同实例之间互不影响;例外:锁对象是*.class(synchronized (*.class){}这种类型)以及synchronized修饰的是static时。所有对象共用同一把锁(对应2、3、4、6这几种情况) - 无论方法是正常执行完毕,还是抛出异常。都会释放锁(对应第7种情况) - 使用synchronized注意点:锁对象不能为空、作用域不能过大,避难死锁。 参考 慕课网课程 [Java高并发之魂:synchronized深度解析](https://www.imooc.com/learn/1086)
保存文章