synchronized (this)原理:涉及两条指令:monitorenter,monitorexit;再说同步方法,从同步方法反编译的结果来看,方法的同步并没有通过指令monitorenter和monitorexit来实现,相对于普通方法,其常量池中多了ACC_SYNCHRONIZED标示符。
JVM就是根据该标示符来实现方法的同步的:当方法被调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。
synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。synchronized既可以加在一段代码上,也可以加在方法上。
class Sync { public synchronized void test() { System.out.println("test开始.."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); } } class MyThread extends Thread { public void run() { Sync sync = new Sync(); sync.test(); } } public class Main { public static void main(String[] args) { for (int i = 0; i < 3; i++) { Thread thread = new MyThread(); thread.start(); } } }
运行结果: test开始.. test开始.. test开始.. test结束.. test结束.. test结束..
上面的程序起了三个线程,同时运行Sync类中的test()方法,虽然test()方法加上了synchronized,但是还是同时运行起来,貌似synchronized没起作用。
注意:synchronized()锁住的是括号里的对象,而不是代码。对于非static的synchronized方法,锁的就是对象本身也就是this。
则可以这样:
class Sync { public void test() { synchronized (Sync.class) { System.out.println("test开始.."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("test结束.."); } } } class MyThread extends Thread { public void run() { Sync sync = new Sync(); sync.test(); } } public class Main { public static void main(String[] args) { for (int i = 0; i < 3; i++) { Thread thread = new MyThread(); thread.start(); } } }
运行结果: test开始.. test结束.. test开始.. test结束.. test开始.. test结束..
上面代码用synchronized(Sync.class)实现了全局锁的效果。
static synchronized方法,static方法可以直接类名加方法名调用,方法中无法使用this,所以它锁的不是this,而是类的Class对象,所以,static synchronized方法也相当于全局锁,相当于锁住了该整个方法的代码段。