synchronized 关键字
关键字 synchronized 获取的锁都是对象锁 , 而不是把一段代码 (方法) 当作锁 , 代码中哪个线程先执行 synchronized 关键字修饰的方法 , 哪个线程就持有该方法所属对象的锁 , 两个对象获取的就是两个不同的锁 , 互不干扰。
有一种情况则是相同的锁 , 即在静态方法上加 synchronized 关键字 , 表示锁定 .class 类 , 类一级别的锁 (独占 .class 类)。
1 package com.itdoc.multi.sync002; 2 3 /** 4 * 关键字 synchronized 获取的锁都是对象锁, 而不是把一段代码 (方法) 当作锁, 5 * 代码中哪个线程先执行 synchronized 关键字修饰的方法, 哪个线程就持有该方法所属对象的锁, 两个对象获取的就是两个不同的锁, 互不干扰。 6 * 7 * synchronized 关键字修饰静态方法, 标识锁定 .class 类, 类一级别的锁 (独占 .class 类) 8 * @author Wáng Chéng Dá 9 * @create 2017-03-20 8:24 10 */ 11 public class MultiThread { 12 13 private static int num = 0; 14 15 public static synchronized void pointNum(String tag) { 16 try { 17 if ("a".equals(tag)) { 18 num = 100; 19 System.out.println(Thread.currentThread().getName() + " -->> tag is a , set num over!"); 20 Thread.sleep(4000); 21 } else { 22 num = 200; 23 System.out.println(Thread.currentThread().getName() + " -->> tag is b , set num over!" ); 24 } 25 System.out.println(Thread.currentThread().getName() + " -->> tag : " + tag + ", num = " + num); 26 } catch (InterruptedException e) { 27 e.printStackTrace(); 28 } 29 } 30 31 public static void main(String[] args) { 32 33 //创建两个不同的对象 34 final MultiThread m1 = new MultiThread(); 35 final MultiThread m2 = new MultiThread(); 36 37 Thread t1 = new Thread(new Runnable() { 38 @Override 39 public void run() { 40 m1.pointNum("a"); 41 // m2.pointNum("b"); 42 } 43 }, "t1"); 44 45 Thread t2 = new Thread(new Runnable() { 46 @Override 47 public void run() { 48 // m1.pointNum("b"); 49 m2.pointNum("b"); 50 } 51 }, "t2"); 52 t1.start(); 53 t2.start(); 54 } 55 }
asynchronized | synchronized | static synchronized | 分析 | |
相同线程相同对象 |
t1 -->> tag is a , set num over! ------------sleep 4 s------------- t1 -->> tag : a, num = 100 t1 -->> tag is b , set num over! t1 -->> tag : b, num = 200 |
t1 -->> tag is a , set num over! ------------sleep 4 s------------- t1 -->> tag : a, num = 100 t1 -->> tag is b , set num over! t1 -->> tag : b, num = 200 |
t1 -->> tag is a , set num over! ------------sleep 4 s------------- t1 -->> tag : a, num = 100 t1 -->> tag is b , set num over! t1 -->> tag : b, num = 200 |
按顺序执行,不存在相互干扰问题。 |
相同线程不同对象 |
t1 -->> tag is a , set num over! ------------sleep 4 s------------- t1 -->> tag : a, num = 100 t1 -->> tag is b , set num over! t1 -->> tag : b, num = 200 |
t1 -->> tag is a , set num over! ------------sleep 4 s------------- t1 -->> tag : a, num = 100 t1 -->> tag is b , set num over! t1 -->> tag : b, num = 200 |
t1 -->> tag is a , set num over! ------------sleep 4 s------------- t1 -->> tag : a, num = 100 t1 -->> tag is b , set num over! t1 -->> tag : b, num = 200 |
按顺序执行,不存在相互干扰问题 |
不同线程相同对象 |
t1 -->> tag is a , set num over! t2 -->> tag is b , set num over! t2 -->> tag : b, num = 200 ------------sleep 4 s------------- t1 -->> tag : a, num = 200 |
t1 -->> tag is a , set num over! ------------sleep 4 s------------- t1 -->> tag : a, num = 100 t2 -->> tag is b , set num over! t2 -->> tag : b, num = 200 |
t1 -->> tag is a , set num over! ------------sleep 4 s------------- t1 -->> tag : a, num = 100 t2 -->> tag is b , set num over! t2 -->> tag : b, num = 200 |
不用 synchronized 修饰时,线程是不安全的,线程 t1 执行过程中,t2 线程也开始执行这段代码,在 t1 线程睡眠时,t2 线程执行完成将 num 值更改,所以 t1 线程也打印 t2 修改后的结果。添加修饰时,在 t1 线程完成释放锁后 t2 线程才开始执行。 |
不同线程不同对象 |
t1 -->> tag is a , set num over! t2 -->> tag is b , set num over! t2 -->> tag : b, num = 200 ------------sleep 4 s------------- t1 -->> tag : a, num = 100 |
t1 -->> tag is a , set num over! t2 -->> tag is b , set num over! t2 -->> tag : b, num = 200 ------------sleep 4 s------------- t1 -->> tag : a, num = 100 |
t1 -->> tag is a , set num over! ------------sleep 4 s------------- t1 -->> tag : a, num = 100 t2 -->> tag is b , set num over! t2 -->> tag : b, num = 200 |
无修饰和 synchronized 修饰时,不存在相互干扰问题,在 t1 线程执行当中,t2 线程也会执行,运行行为也是正常的。static synchronized 修饰时,只有t1线程执行完成释放锁之后 t2 线程才开始执行。这时候是类一级别的锁。 |