java线程安全之synchronized代码块(六)
来源:互联网 发布:java线程池中线程状态 编辑:程序博客网 时间:2024/06/11 19:46
科技快讯
今天是中国航天科技集团公司一院的60岁生日。作为中国运载火箭的摇篮,从长征一号运载火箭到新一代运载火箭长征五号、长征七号,多型飞天利箭都诞生在这里。
近日,这里又传来关于航天运输系统未来发展的新消息。在第一届中国航天运输系统发展论坛上,一院发布《2017—2045年航天运输系统发展路线图》学术成果,系统规划航天运输系统的能力建设前景与发展蓝图,进一步落实党的十九大提出的建设航天强国的战略目标。
正文
使用synchronized声明的方法在某些情况下是有弊端的,比线程调用同步的方法执行一个很长时间的任务,那么B线程就必须等待比较长的时间才能执行,这样的情况下可以使用synchronized代码块去优化代码执行时间,也就是通常所说的减小锁的粒度。
案例如下:
public class Optimize { public void doLongTimeTask(){ try { System.out.println("当前线程开始:" + Thread.currentThread().getName() + ", 正在执行一个较长时间的业务操作,其内容不需要同步"); Thread.sleep(2000); synchronized(this){ System.out.println("当前线程:" + Thread.currentThread().getName() + ", 执行同步代码块,对其同步变量进行操作"); Thread.sleep(1000); } System.out.println("当前线程结束:" + Thread.currentThread().getName() + ", 执行完毕"); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { final Optimize otz = new Optimize(); Thread t1 = new Thread(new Runnable() { @Override public void run() { otz.doLongTimeTask(); } },"t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { otz.doLongTimeTask(); } },"t2"); t1.start(); t2.start(); }}
打印结果:
当前线程开始:t1, 正在执行一个较长时间的业务操作,其内容不需要同步当前线程开始:t2, 正在执行一个较长时间的业务操作,其内容不需要同步当前线程:t2, 执行同步代码块,对其同步变量进行操作当前线程:t1, 执行同步代码块,对其同步变量进行操作当前线程结束:t2, 执行完毕当前线程结束:t1, 执行完毕
synchronized可以使用任意的Object进行加锁,用法比较灵活。
案例如下:
public class ObjectLock { public void method1(){ synchronized (this) { //对象锁 try { System.out.println("do method1.."); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } public void method2(){ synchronized (ObjectLock.class) {//类锁 try { System.out.println("do method2.."); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } private Object lock = new Object(); public void method3(){ synchronized (lock) {//任何对象锁 try { System.out.println("do method3.."); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { final ObjectLock objLock = new ObjectLock(); Thread t1 = new Thread(new Runnable() { @Override public void run() { objLock.method1(); } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { objLock.method2(); } }); Thread t3 = new Thread(new Runnable() { @Override public void run() { objLock.method3(); } }); t1.start(); t2.start(); t3.start(); }}
打印结果:
do method1..do method2..do method3..
另外特别注意一个问题,就是不要使用string的常量加锁,会出现死循环问题。
案例如下:
public class StringLock { public void method() { synchronized ("字符串常量") { try { while(true){ System.out.println("当前线程 : " + Thread.currentThread().getName() + "开始"); Thread.sleep(1000); System.out.println("当前线程 : " + Thread.currentThread().getName() + "结束"); } } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { final StringLock stringLock = new StringLock(); Thread t1 = new Thread(new Runnable() { @Override public void run() { stringLock.method(); } },"t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { stringLock.method(); } },"t2"); t1.start(); t2.start(); }
打印结果(这里是死循环一直都是t1线程在执行,使用string的常量加锁,会出现死循环问题):
当前线程 : t1开始当前线程 : t1结束当前线程 : t1开始当前线程 : t1结束当前线程 : t1开始当前线程 : t1结束当前线程 : t1开始当前线程 : t1结束当前线程 : t1开始
锁对象的改变问题,当使用一个对象讲行加锁的时候,要注意对象本身发生改变的时候,那么持有的锁就不同。如果对象本身不发生改变,那么依然是同步的,即使是对象的属性发生了改变。
案例如下:
public class ModifyLock { private String name ; private int age ; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public synchronized void changeAttributte(String name, int age) { try { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 开始"); this.setName(name); this.setAge(age); System.out.println("当前线程 : " + Thread.currentThread().getName() + " 修改对象内容为: " + this.getName() + ", " + this.getAge()); Thread.sleep(2000); System.out.println("当前线程 : " + Thread.currentThread().getName() + " 结束"); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { final ModifyLock modifyLock = new ModifyLock(); Thread t1 = new Thread(new Runnable() { @Override public void run() { modifyLock.changeAttributte("张三", 20); } },"t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { modifyLock.changeAttributte("李四", 21); } },"t2"); t1.start(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } t2.start(); }}
打印结果:
当前线程 : t1 开始当前线程 : t1 修改对象内容为: 张三, 20当前线程 : t1 结束当前线程 : t2 开始当前线程 : t2 修改对象内容为: 李四, 21当前线程 : t2 结束
死锁问题,在设计程序时就应该避免双方相互持有对方的锁的情况:
案例如下:
public class DeadLock implements Runnable{ private String tag; private static Object lock1 = new Object(); private static Object lock2 = new Object(); public void setTag(String tag){ this.tag = tag; } @Override public void run() { if(tag.equals("a")){ synchronized (lock1) { try { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock1执行"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock2) { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock2执行"); } } } if(tag.equals("b")){ synchronized (lock2) { try { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock2执行"); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock1) { System.out.println("当前线程 : " + Thread.currentThread().getName() + " 进入lock1执行"); } } } } public static void main(String[] args) { DeadLock d1 = new DeadLock(); d1.setTag("a"); DeadLock d2 = new DeadLock(); d2.setTag("b"); Thread t1 = new Thread(d1, "t1"); Thread t2 = new Thread(d2, "t2"); t1.start(); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } t2.start(); }}
打印结果:
当前线程 : t1 进入lock1执行当前线程 : t2 进入lock2执行
源代码:https://github.com/hfbin/Thread_Socket/tree/master/Thread/sync006
- java线程安全之synchronized代码块(六)
- java线程安全之synchronized同步代码块解决脏读问题(四)
- java 学习之路——线程2(synchronized静态代码块)
- 线程(六)--线程同步--synchronized(同步代码块,同步方法)
- java线程安全之同步函数和同步代码块
- 不变对象替代synchronized代码块,实现线程安全
- 线程之synchronized 块
- java线程安全之synchronized理解篇(一)
- 【Java】 线程安全 synchronized
- (二) Java多线程详解之Synchronized同步代码块和线程通信详解
- java多线程之-----静态同步synchronized方法与synchronized(class) 代码块
- java中的synchronized实例(代码块)
- JAVA——线程安全(synchronized)
- Java中线程安全(synchronized)
- java中synchronized修饰代码块(两种创建线程的方式讲解卖票程序)
- (六)java并发编程--synchronized同步块
- java synchronized详解--synchronized代码块
- JAVA 同步代码块synchronized
- 破解office 工作表保护
- 判断一个时间是否属于周末
- [ArcGIS] 空间分析(一) 空间数据的转换与处理
- c语言基础(三)
- P2020 ( e500核 ) 上电启动及uboot流程(转)
- java线程安全之synchronized代码块(六)
- 机器学习实战笔记-预测数值型数据:回归
- PRIMARY KEY与identity(1,1)的比较 原创 2016年03月11日 11:08:13 标签:SQL Server /primary key /identity 1572 PRIMA
- 开关问题 POJ
- 菜鸡的R语言学习笔记——数据结构 Part 2
- 关于c++类的思考
- 2710 1-4 输出菱形
- 【python】Flask解决跨域的问题
- matlab中如何导入excel数据