Open penglongli opened 6 years ago
synchronized 是 Java 用来同步的关键字,它修饰的类型如下:
目前其性能虽然得到了提升,但是仍然不建议使用
public class Test { static class InnerClass { public void execute() { synchronized (this) { System.out.println(Thread.currentThread().getName() + " get lock"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } } static class MyRunnable implements Runnable { InnerClass innerClass; MyRunnable(InnerClass innerClass) { this.innerClass = innerClass; } @Override public void run() { innerClass.execute(); } } public static void main(String[] args) { InnerClass innerClass = new InnerClass(); Thread t1 = new Thread(new MyRunnable(innerClass)); Thread t2 = new Thread(new MyRunnable(innerClass)); t1.start(); t2.start(); } }
输出:
Thread-0 get lock // 等待了 2s Thread-1 get lock
public class Test { static class InnerClass { public synchronized void execute() { System.out.println(Thread.currentThread().getName() + " get lock"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } static class MyRunnable implements Runnable { InnerClass innerClass; MyRunnable(InnerClass innerClass) { this.innerClass = innerClass; } @Override public void run() { innerClass.execute(); } } public static void main(String[] args) { InnerClass innerClass = new InnerClass(); Thread t1 = new Thread(new MyRunnable(innerClass)); Thread t2 = new Thread(new MyRunnable(innerClass)); t1.start(); t2.start(); } }
如果上述两个线程使用的 InnerClass 对象不同,则不会等待 2s,两个线程也不会出现阻塞同步的情况。
public class Test { static class InnerClass { public synchronized static void execute() { System.out.println(Thread.currentThread().getName() + " get lock"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } static class MyRunnable implements Runnable { @Override public void run() { InnerClass.execute(); } } public static void main(String[] args) { Thread t1 = new Thread(new MyRunnable()); Thread t2 = new Thread(new MyRunnable()); t1.start(); t2.start(); } }
修饰静态方法时候,拿到的是基于类的锁
public class Test { static class MyRunnable implements Runnable { @Override public void run() { synchronized (MyRunnable.class) { System.out.println(Thread.currentThread().getName() + " get lock"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { Thread t1 = new Thread(new MyRunnable()); Thread t2 = new Thread(new MyRunnable()); t1.start(); t2.start(); } }
由于我们把同步关键字加到了 MyRunnable 类上,同一时刻只能由一个 Thread 来获得同步锁,另一个线程发生阻塞
public class Test { static final InnerClass innerClass = new InnerClass(); static class InnerClass { public void execute() { synchronized (innerClass) { System.out.println(Thread.currentThread().getName() + " get lock"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } } static class MyRunnable implements Runnable { InnerClass innerClass; MyRunnable(InnerClass innerClass) { this.innerClass = innerClass; } @Override public void run() { innerClass.execute(); } } public static void main(String[] args) { Thread t1 = new Thread(new MyRunnable(innerClass)); Thread t2 = new Thread(new MyRunnable(innerClass)); Thread t3 = new Thread(new MyRunnable(innerClass)); t1.start(); t2.start(); t3.start(); } }
Thread-0 get lock // 等待 2s Thread-2 get lock // 等待 2s Thread-1 get lock
为什么只能是修饰 final 对象?
这句话说得很好:
if the object reference changes, the same section of code may be run in parallel 如果对象引用改变,相同的代码可能会出现并行执行的问题
我们的 synchronized 是对对象的引用加锁,如果对象引用改变了,此处的同步就没什么意义了。
如下:
ublic class Test2 { static InnerClass innerClass = new InnerClass(); static class InnerClass { public void execute() { synchronized (innerClass) { System.out.println(Thread.currentThread().getName() + " get lock"); innerClass = new InnerClass(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } } static class MyRunnable implements Runnable { InnerClass innerClass; MyRunnable(InnerClass innerClass) { this.innerClass = innerClass; } @Override public void run() { innerClass.execute(); } } public static void main(String[] args) { Thread t1 = new Thread(new MyRunnable(innerClass)); Thread t2 = new Thread(new MyRunnable(innerClass)); Thread t3 = new Thread(new MyRunnable(innerClass)); Thread t4 = new Thread(new MyRunnable(innerClass)); Thread t5 = new Thread(new MyRunnable(innerClass)); Thread t6 = new Thread(new MyRunnable(innerClass)); t1.start(); t2.start(); t3.start(); t4.start(); t5.start(); t6.start(); } }
上述的几个线程会出现并行执行的情况。
public class Test { static final Message message = new Message(); static class Message { String msg; void setMsg(String msg) { System.out.println(msg); this.msg = msg; } } static class PassengerRunnable implements Runnable { @Override public void run() { synchronized (message) { try { message.setMsg("乘客:司机,我位置准确,请来接我"); message.notify(); // 等待司机赶到定位地址 message.wait(); // 乘客赶往定位地址 Thread.sleep(2000); System.out.println("乘客:好了,我也到了"); } catch (InterruptedException e) { e.printStackTrace(); } } } } static class DriverRunnable implements Runnable { @Override public void run() { synchronized (message) { try { message.wait(); // 司机赶往目标地点 Thread.sleep(2000); message.setMsg("司机:我已到达定位地址,速来"); message.notify(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws InterruptedException { DriverRunnable driver = new DriverRunnable(); PassengerRunnable passenger = new PassengerRunnable(); new Thread(driver).start(); Thread.sleep(1000); new Thread(passenger).start(); } }
上边是 wait 和 notify 的简单使用,场景并不太合适。
synchronized 是 Java 用来同步的关键字,它修饰的类型如下:
目前其性能虽然得到了提升,但是仍然不建议使用
synchroized 使用
修饰代码块
输出:
修饰方法
输出:
如果上述两个线程使用的 InnerClass 对象不同,则不会等待 2s,两个线程也不会出现阻塞同步的情况。
修饰静态方法
输出:
修饰静态方法时候,拿到的是基于类的锁
修饰类
输出:
由于我们把同步关键字加到了 MyRunnable 类上,同一时刻只能由一个 Thread 来获得同步锁,另一个线程发生阻塞
修饰 final 对象
输出:
为什么只能是修饰 final 对象?
这句话说得很好:
我们的 synchronized 是对对象的引用加锁,如果对象引用改变了,此处的同步就没什么意义了。
如下:
上述的几个线程会出现并行执行的情况。
wait 与 notify
上边是 wait 和 notify 的简单使用,场景并不太合适。