多线程:Java内置锁与synchronized关键字

Java提供了一种内置的锁机制来支持原子性

每一个Java对象都可以用作一个实现同步的锁,称为内置锁,线程进入同步代码块之前自动获取到锁,代码块执行完成正常退出或代码块中抛出异常退出时会释放掉锁

内置锁为互斥锁,即线程A获取到锁后,线程B阻塞直到线程A释放锁,线程B才能获取到同一个锁

内置锁使用synchronized关键字实现,synchronized关键字有两种用法:

1,修饰需要进行同步的方法(所有访问状态变量的方法都必须进行同步),此时充当锁的对象为调用同步方法的对象

[java]  view plain  copy
  1. public class Test{  
  2.     private int count = 0;  
  3.       
  4.     public synchronized int add(){  
  5.         count += 1;  
  6.         return count;  
  7.     }  
  8.       
  9.     public synchronized int delete(){  
  10.         count -= 1;  
  11.         return count;  
  12.     }  
  13. }  

2,同步代码块

和直接使用synchronized修饰需要同步的方法是一样的,但是锁的粒度可以更细,并且充当锁的对象不一定是this,也可以是其它对象,所以使用起来更加灵活

[java]  view plain  copy
  1. public class Test{  
  2.     private int count = 0;  
  3.       
  4.     public int add(){  
  5.         synchronized(this){  
  6.             count += 1;  
  7.         }  
  8.         return count;  
  9.     }  
  10.       
  11.     public int delete(){  
  12.         synchronized(this){  
  13.             count -= 1;  
  14.         }  
  15.         return count;  
  16.     }  
  17. }  

用synchronized关键字修饰的方法可以认为是一个横跨整个方法体的同步代码块

[java]  view plain  copy
  1. public class Status {  
  2.     private int num = 0;  
  3.       
  4.     public void selfIncrease(){  
  5.         num = num + 1;  
  6.         System.out.println(Thread.currentThread().getName()     
  7.                 + "|" + num);  
  8.     }  
  9. }  
[java]  view plain  copy
  1. public class Task implements Runnable {  
  2.     private Status status;  
  3.       
  4.     public Task(Status status){  
  5.         this.status = status;  
  6.     }  
  7.       
  8.     public void run() {  
  9.         synchronized (status) {  
  10.             status.selfIncrease();  
  11.         }  
  12.     }  
  13.       
  14.     public static void main(String[] args) {  
  15.         Status status = new Status();  
  16.         Task task = new Task(status);  
  17.         Thread t1 = new Thread(task);  
  18.         Thread t2 = new Thread(task);  
  19.         Thread t3 = new Thread(task);  
  20.         Thread t4 = new Thread(task);  
  21.         t1.start();  
  22.         t2.start();  
  23.         t3.start();  
  24.         t4.start();  
  25.     }  
  26. }  

运行结果为:

[plain]  view plain  copy
  1. Thread-0|1  
  2. Thread-3|2  
  3. Thread-2|3  
  4. Thread-1|4  

修改上面的代码,每个线程运行时创建一个新的Status对象,而不是像上面的代码,4个线程共用同一个Status对象:

[java]  view plain  copy
  1. public class Task implements Runnable {  
  2.     public void run() {  
  3.         Status status = new Status();  
  4.         synchronized (status) {  
  5.             status.selfIncrease();  
  6.         }  
  7.     }  
  8.       
  9.     public static void main(String[] args) {  
  10.         Task task = new Task();  
  11.         Thread t1 = new Thread(task);  
  12.         Thread t2 = new Thread(task);  
  13.         Thread t3 = new Thread(task);  
  14.         Thread t4 = new Thread(task);  
  15.         t1.start();  
  16.         t2.start();  
  17.         t3.start();  
  18.         t4.start();  
  19.     }  
  20. }  

由于充当锁的对象实例不一定是同一个对象(hashcode不同),同步失效:

[plain]  view plain  copy
  1. Thread-0|1  
  2. Thread-1|1  
  3. Thread-3|1  
  4. Thread-2|1  

因此同步代码块中充当锁的对象必须为同一个对象

[java]  view plain  copy
  1. public class Task implements Runnable {  
  2.     private Status status;  
  3.       
  4.     public Task(Status status){  
  5.         this.status = status;  
  6.     }  
  7.       
  8.     public void run() {  
  9.         synchronized (status) {  
  10.             System.out.println("Thread lock");  
  11.             System.out.println("Thread:" + status.getNum());  
  12.             System.out.println("Thread over");  
  13.   
  14.         }  
  15.     }  
  16.       
  17.     public static void main(String[] args) {  
  18.         Status status = new Status();  
  19.         Task task = new Task(status);  
  20.         Thread t = new Thread(task);  
  21.         t.start();  
  22.         //synchronized(status){  
  23.             System.out.println("Main");  
  24.             status.setNum(1);  
  25.             System.out.println("Main:" + status.getNum());  
  26.         //}  
  27.     }  
  28. }  

运行结果为:

[plain]  view plain  copy
  1. Main  
  2. Thread lock  
  3. Main:1  
  4. Thread:1  
  5. Thread over  

从运行结果可以看出,在Thread线程锁定status对象的时候,Main线程在Thread线程释放锁对象前依然能够修改status对象的num域,说明锁没有生效

Main线程中没有对status对象进行同步,故在Thread线程锁定status对象的时候不需要阻塞,可以直接操作status对象,因此所有使用同步对象的地方都必须进行同步

修改方式为:Task类的main方法中,在操作status对象时进行同步(去掉代码中的注释部分)

如果锁对象为静态变量,或使用synchronized关键字修饰静态方法,则锁对象为Class对象

[java]  view plain  copy
  1. public class Status {  
  2.     private static int num = 0;  
  3.       
  4.     public synchronized static void selfIncrease(){  
  5.         num = num + 1;  
  6.         System.out.println(Thread.currentThread().getName()     
  7.                 + "|" + num);  
  8.     }  
  9. }  
[java]  view plain  copy
  1. public class Task implements Runnable {  
  2.       
  3.     public void run() {  
  4.         Status.selfIncrease();  
  5.     }  
  6.       
  7.     public static void main(String[] args) throws Exception {  
  8.         Task task = new Task();  
  9.         Thread t1 = new Thread(task);  
  10.         Thread t2 = new Thread(task);  
  11.         Thread t3 = new Thread(task);  
  12.         Thread t4 = new Thread(task);  
  13.         t1.start();  
  14.         t2.start();  
  15.         t3.start();  
  16.         t4.start();  
  17.     }  
  18. }  

运行结果如下:

[plain]  view plain  copy
  1. Thread-0|1  
  2. Thread-1|2  
  3. Thread-3|3  
  4. Thread-2|4  

相当于:

[java]  view plain  copy
  1. public class Status {  
  2.     private static int num = 0;  
  3.       
  4.     public static void selfIncrease(){  
  5.         synchronized(Status.class){  
  6.             num = num + 1;  
  7.             System.out.println(Thread.currentThread().getName()     
  8.                     + "|" + num);  
  9.         }  
  10.     }  
  11. }  

或是:

[java]  view plain  copy
  1. public class Status {  
  2.     private static int num = 0;  
  3.     private static Object lock = new Object();  
  4.       
  5.     public static void selfIncrease(){  
  6.         synchronized(lock){  
  7.             num = num + 1;  
  8.             System.out.println(Thread.currentThread().getName()     
  9.                     + "|" + num);  
  10.         }  
  11.     }  
  12. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值