Java并发编程(3)——synchronized
来源:互联网 发布:水妖钢笔 知乎 编辑:程序博客网 时间:2024/06/08 09:41
在Java中可以使用synchronized关键字来修饰方法、静态方法和代码块,synchronized能够隐式的获取和释放锁,从而保证在同一时刻,只有一个线程在方法或代码块中。
public class SynchronizedDemo { public static int num = 0; public static void main(String[] args) { SynchronizedDemo demo = new SynchronizedDemo(); new Thread(new DemoRunnable(demo), "T1").start(); new Thread(new DemoRunnable(demo), "T2").start(); } public synchronized void test(){ for(int i=0; i<3; i++) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" num = "+num++); } } static class DemoRunnable implements Runnable{ private SynchronizedDemo demo; public DemoRunnable(SynchronizedDemo demo){ this.demo = demo; } @Override public void run() { demo.test(); } }}
对test()使用synchronized修饰时,输出为:
T1 num = 0T1 num = 1T1 num = 2T1 num = 3T1 num = 4T2 num = 5T2 num = 6T2 num = 7T2 num = 8T2 num = 9
当去掉synchronized时,输出为:
T2 num = 1T1 num = 0T1 num = 2T2 num = 3T1 num = 5T2 num = 4T1 num = 6T2 num = 6T2 num = 7T1 num = 7
当synchronized修饰方法时,锁的对象是类的当前实例。
我们对上面的代码中的test()进行改写:
public synchronized void test(){ System.out.println(Thread.currentThread().getName()+" START time= "+new Date()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" END time= "+new Date()); }
两个线程使用同一个 demo 对象,查看输出可知只有等待其中一个线程结束后,另一个线程才执行test():
public static void main(String[] args) { SynchronizedDemo demo = new SynchronizedDemo(); new Thread(new DemoRunnable(demo), "T1").start(); new Thread(new DemoRunnable(demo), "T2").start();}
输出为:
T1 START time= Mon Aug 14 13:02:40 CST 2017T1 END time= Mon Aug 14 13:02:42 CST 2017T2 START time= Mon Aug 14 13:02:42 CST 2017T2 END time= Mon Aug 14 13:02:44 CST 2017
两个线程分别使用一个 demo对象,则两个线程的开始和结束互不影响:
public static void main(String[] args) { new Thread(new DemoRunnable(new SynchronizedDemo()), "T1").start(); new Thread(new DemoRunnable(new SynchronizedDemo()), "T2").start();}
输出为:
T1 START time= Mon Aug 14 12:58:58 CST 2017T2 START time= Mon Aug 14 12:58:58 CST 2017T2 END time= Mon Aug 14 12:59:00 CST 2017T1 END time= Mon Aug 14 12:59:00 CST 2017
当synchronized修饰静态方法时,锁的对象是当前类的class对象
我们将上面的test() 改为静态方法,然后执行上面的测试代码,发现两个线程先后执行。
两种测试方法输出都为:
T1 START time= Mon Aug 14 13:04:06 CST 2017T1 END time= Mon Aug 14 13:04:08 CST 2017T2 START time= Mon Aug 14 13:04:08 CST 2017T2 END time= Mon Aug 14 13:04:10 CST 2017
当synchronized修饰代码块时,锁的对象是指定的对象。
修改上面的test():
public Object lock = new Object();public static void main(String[] args) { SynchronizedDemo demo = new SynchronizedDemo(); new Thread(new DemoRunnable(demo), "T1").start(); new Thread(new DemoRunnable(demo), "T2").start();}public void test(){ System.out.println(Thread.currentThread().getName()+" START time= "+new Date()); synchronized(lock){ System.out.println(Thread.currentThread().getName()+" code block START time= "+new Date()); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" code block end time= "+new Date()); } System.out.println(Thread.currentThread().getName()+" END time= "+new Date()); }
输出结果为:
T2 START time= Mon Aug 14 15:07:26 CST 2017T2 code block START time= Mon Aug 14 15:07:26 CST 2017T1 START time= Mon Aug 14 15:07:26 CST 2017T2 code block end time= Mon Aug 14 15:07:28 CST 2017T1 code block START time= Mon Aug 14 15:07:28 CST 2017T2 END time= Mon Aug 14 15:07:28 CST 2017T1 code block end time= Mon Aug 14 15:07:30 CST 2017T1 END time= Mon Aug 14 15:07:30 CST 2017
由输出可以看出对于同步代码块,同一时间只能有一个线程访问。
由synchronized修饰的同步块,如果抛出异常,则锁自动释放。
修改上面的test方法:
public static void main(String[] args) throws InterruptedException { SynchronizedDemo demo = new SynchronizedDemo(); new Thread(new DemoRunnable(demo), "T1").start(); Thread.sleep(50);//延时创建线程2,使线程1先执行 new Thread(new DemoRunnable(demo), "T2").start(); } public void test(){ System.out.println(Thread.currentThread().getName()+" START time= "+new Date()); synchronized(lock){ System.out.println(Thread.currentThread().getName()+" code block START time= "+new Date()); try { //使线程1抛出异常 if("T1".equals(Thread.currentThread().getName())){ throw new RuntimeException(); } Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" code block end time= "+new Date()); } System.out.println(Thread.currentThread().getName()+" END time= "+new Date()); }
由输出结果可以看出,线程T1抛出异常,没有继续执行,而线程T2直接获取了锁。
synchroniced同步块对于同一个线程来说是可重入的,不回出现自己把自己锁死的问题。
下面的例子说明了这个问题:
public class SynchronizedReentrantTest { public static void main(String[] args) { test(); } public static synchronized void test(){ System.out.println("abc"); demo(); System.out.println("ghi"); } public static synchronized void demo(){ System.out.println("def"); }}
输出结果:
abcdefghi
在代码中,test方法已经持有了class对象的锁,在没有释放的情况下,依然执行了demo方法。
阅读全文
0 0
- Java并发编程(3)——synchronized
- 【Java并发编程实战】—–synchronized
- 【Java并发编程实战】—–synchronized
- 【Java并发编程实战】—–synchronized
- 【Java并发编程实战】—–synchronized
- Java并发编程:synchronized
- Java并发编程:synchronized
- Java并发编程:synchronized
- Java并发编程:synchronized
- Java并发编程:synchronized
- Java并发编程:synchronized
- Java并发编程:synchronized
- Java并发编程:synchronized
- Java并发编程:synchronized
- Java并发编程:synchronized
- Java并发编程:synchronized
- Java并发编程:synchronized
- Java并发编程:synchronized
- Oracle中varchar,varchar2,nvarchar,nvarchar2的区别
- Mongo---配置多数据源
- 什么是梯度下降法?????
- 小白学tkinter(Canvas组件(画布))
- kaldi中的深度神经网络
- Java并发编程(3)——synchronized
- 扫地机器人行走路线
- libcudart.so.8.0: cannot open shared object file: No such file or directory
- Python线性回归实例--Python,sklearn,LinearRegression
- jsp 前台显示的数字保留两位小数的方法
- Userspace RCU 安装过程记录
- 解决coursera课程国内打不开的问题
- explain的用法详解
- C++对象模型(The C++ Object Model)