1.当 synchronized A方法被一个线程调用的时候(运行过程中), 另外一个线程调用A方法会block住,而并不是请求失败,如果此时在block住的线程实例上调用interrupt方法就会触发InterruptedException,然后请求的序列会被cache在请求队列中,在队列中的顺序并不一定是你代码从上到下的运行顺序,而是未知的,这个队列可以cache住的任务数量可以很大, 直到耗光所有内存为止。
public class Test_synchronized { private int a = 0; public static void main(String[] args) { final Test_synchronized sy = new Test_synchronized(); for (int i = 0; i < 99; i++) { final int tmp = i; new Thread(new Runnable() { @Override public void run() { sy.A(tmp); } }).start(); } //当控制台输出 --->end的时候 就意味着所有的线程都开始运行了 System.out.println("----> end"); } //改变共享变量 a 这个方法会sleep 3 秒钟 public synchronized void A(int num) { try { Thread.sleep(0); } catch (InterruptedException e) { e.printStackTrace(); } a = num; System.out.println(a); } }
运行结果:
0 2 3 1 4 5 6 7 8 ----> end 9
2. synchronized 不能直接锁定一个变量(private synchronized int c 这个是错误的),因为java的同步时基于对象的对象锁(官方叫法为监视器),而变量不是对象,这里应该这样理解,Object o = new Object(); o 是指向一定对象的,也就是“=” 右边的东西是对象, 而a只是一个占用4个字节的指针, 所以a并不是对象,那么也就不能锁住变量了。 但是如果用synchronized(变量){}这里可以用变量,因为这里是一个引用,就是指针指向的那个对象。
3. synchronized (obj){ ... } 其中obj就是对象锁,这个对象锁可以理解为是一个标记,那为什么要用对象而不用普通类型做标记,因为java是基于对象的语言,即使同一个类的不同对象实例也会拥有不同的hashcode,也就是唯一的标示,就像身份证一样。
当synchronized 方法运行的时候,JVM会读对象锁的计数器,如果为0就可以放行,如果不为0就要等别人释放这个方法的对象锁。
其实可以理解为对象锁可以和synchronized 方法没有任何关系,对象锁仅仅只是一个标记,并且这个标记必须为对象,就像是你每回去电影院看电影都会买到一张不同的票,票是完整的就证明没看过,检票后,票会被撕开一部分,就证明这张票看过了。
所以 synchronized 只要传入的是一样的对象锁,那么就可以锁住不同的代码块,字符串也行,就是 "" 这样的空字符串也行。
public class Test_synchronized_2 { //如果运行结果都是一般长的就代表线程同步了,如果出现b --- > thread id == 1 2a ---> thread id == 8 1这样的结果 //就证明a方法走到了print后还没有运行println, b方法就运行print了,就是说是费线程同步的 public static void main(String[] args) { final Test_synchronized_2 sy = new Test_synchronized_2(); new Thread(new Runnable() { @Override public void run() { while(true) { sy.a(1); } } }).start(); while(true) { sy.b(2); } } public void a(int flag) { synchronized("123") { //注意这里不会输出换行符哦~!这是print和println的区别啦 System.out.print("a ---> thread id == " + Thread.currentThread().getId() + " " + flag); //注意这里会自动输出换行符哦 System.out.println(); } } public void b(int flag) { synchronized("123") { System.out.print("b --- > thread id == " + Thread.currentThread().getId() + " " + flag); System.out.println(); } } }
a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 b --- > thread id == 1 2 b --- > thread id == 1 2 b --- > thread id == 1 2 b --- > thread id == 1 2 b --- > thread id == 1 2 b --- > thread id == 1 2
public class Test_synchronized_2 { //如果运行结果都是一般长的就代表线程同步了,如果出现b --- > thread id == 1 2a ---> thread id == 8 1这样的结果 //就证明a方法走到了print后还没有运行println, b方法就运行print了,就是说是费线程同步的 public static void main(String[] args) { final Test_synchronized_2 sy = new Test_synchronized_2(); new Thread(new Runnable() { @Override public void run() { while(true) { sy.a(1); } } }).start(); while(true) { sy.b(2); } } public void a(int flag) { synchronized(new String("123")) { //注意这里不会输出换行符哦~!这是print和println的区别啦 System.out.print("a ---> thread id == " + Thread.currentThread().getId() + " " + flag); //注意这里会自动输出换行符哦 System.out.println(); } } public void b(int flag) { //换成new String("123" synchronized(new String("123")) { System.out.print("b --- > thread id == " + Thread.currentThread().getId() + " " + flag); System.out.println(); } } }
b --- > thread id == 1 2 b --- > thread id == 1 2 b --- > thread id == 1 2a ---> thread id == 8 1 b --- > thread id == 1 2 b --- > thread id == 1 2 b --- > thread id == 1 2 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1 a ---> thread id == 8 1b --- > thread id == 1 2 b --- > thread id == 1 2 b --- > thread id == 1 2 b --- > thread id == 1 2 b --- > thread id == 1 2
public class Test_synchronized_3 { public static void main(String[] args) { final Test_synchronized_3 sy = new Test_synchronized_3(); new Thread(new Runnable() { @Override public void run() { while(true) { sy.a(); } } }).start(); while(true) { sy.a(); } } //如果出现11 或者 111或者更多1在同一行,证明该方法没有被锁住. public void a() { synchronized("1") { System.out.print("1"); System.out.println(); } } }
1 1 1 1 1 1 1 1
public class Test_synchronized_3 { public static void main(String[] args) { final Test_synchronized_3 sy = new Test_synchronized_3(); new Thread(new Runnable() { @Override public void run() { while(true) { sy.a(); } } }).start(); while(true) { sy.b(); } } //如果出现11 或者 111或者更多1在同一行,证明该方法没有被锁住. public void a() { synchronized("1") { System.out.print("1"); System.out.println(); } } public void b() { synchronized("2") { System.out.print("2"); System.out.println(); } } }
1 1 1 1 1 2 2 21 1 1 2 2 1