Synchronized的使用
- 修饰静态方法
//修饰静态方法 public static synchronized void print() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"runing"); }
- 修饰非静态方法
//修饰非静态方法 public synchronized void print1() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"runing"); }
- 修饰代码块
//代码块的使用 public void prnit2() { synchronized (this) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"runing"); } } //代码块的使用 public void prnit3() { synchronized (SynchroTest.class) { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"runing"); } }
疑问:修饰代码块的时候,Synchronized参数对象起到了什么作用?
答:当JVM是用ClassLoader加载字节码的时候,会在方法区创建一个对象,同时也会在堆去创建一个Class(注意是大写的)。使用Synchronized.xxx.class就是说明所有Class对应的对象都使用共同一个锁(比较抽象)。这个Class一定是一个final的类。
java中每一个对象都会有一个monitor对象(监视器)。它的作用就是给对象加锁用的。
某一线程战友这个对象的时候,先看monitor的计数器是不是为0,如果是0说明还没有线程占有,此时会将monitor的计数器+1.如果不为0,表示有其他线程占有这个对象,需要等待。当占有这个对象的线程释放这个对象的时候,那么此时会将这个对象的monitor-1(并不是monitor=0,而是-1)。类似于CPU中的cache line作用。
线程堆栈分析
public static void main(String[] args) throws InterruptedException { final SynchroTest tSynchroTest1 = new SynchroTest(); for (int i = 10; i < 15; i++) { new Thread(tSynchroTest1::print1).start(); } } // 修饰非静态方法 public synchronized void print1() { try { TimeUnit.MINUTES.sleep(2); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "runing"); }
根据以上代码进行分析。
jconsole分析,可以看出当前拥有对象锁的Thread-3因为线程睡眠,所以状态为TIMED_WAITING(等待状态)。看Thread-2可以看出总阻止数为1,也就是block状态(上锁状态)。