PHP技术那点事
全部
技术
PHP
MySQL
前端
Linux
JAVA
退出
编辑文章
选择分类
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)
保存文章