Java同步学习(持续更新)
在需要考虑线程安全性的场合,可以考虑以下五种方式来实现线程的安全性:
1.同步方法
即有synchronized关键字修饰的方法。
由于java的每个对象都有一个内置锁,当用此关键字修饰方法时,
1,该类的对象可以被多个线程安全的访问。
2,每个线程调用该对象的任意方法之后,都将得到正确的结果。
3,每个线程调用该对象的任意方法之后,该对象状态依然保持合理状态。
注:synchronized关键字可以修饰方法,也可以修饰代码块,但不能修饰构造器,属性等。
1。每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。
2。将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行
的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。
package com.test; import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement; public class TestDao {
private Connection conn;// ①一个非线程安全的变量 public void addTopic() throws SQLException {
Statement stat = conn.createStatement();// ②引用非线程安全变量
// …
}
}
conn是成员变量,因为addTopic()方法是非线程安全的,必须在使用时创建一个新TopicDao实例(非singleton)。下面使用ThreadLocal对conn这个非线程安全的“状态”进行改造:
TestDao:线程安全
package com.test; import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement; public class TestDaoNew {
// ①使用ThreadLocal保存Connection变量
private static ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>(); public static Connection getConnection() {
// ②如果connThreadLocal没有本线程对应的Connection创建一个新的Connection,
// 并将其保存到线程本地变量中。
if (connThreadLocal.get() == null) {
Connection conn = getConnection();
connThreadLocal.set(conn);
return conn;
} else {
return connThreadLocal.get();// ③直接返回线程本地变量
}
} public void addTopic() throws SQLException {
// ④从ThreadLocal中获取线程对应的Connection
Statement stat = getConnection().createStatement();
}
}
不 同的线程在使用TopicDao时,先判断connThreadLocal.get()是否是null,如果是null,则说明当前线程还没有对应的 Connection对象,这时创建一个Connection对象并添加到本地线程变量中;如果不为null,则说明当前的线程已经拥有了 Connection对象,直接使用就可以了。这样,就保证了不同的线程使用线程相关的Connection,而不会使用其它线程的 Connection。因此,这个TopicDao就可以做到singleton共享了。
当然,这个例子本身很粗糙,将Connection的ThreadLocal直接放在DAO只能做到本DAO的多个方法共享Connection时不 发生线程安全问题,但无法和其它DAO共用同一个Connection,要做到同一事务多DAO共享同一Connection,必须在一个共同的外部类使 用ThreadLocal保存Connection。
ConnectionManager.java
package com.test; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException; public class ConnectionManager { private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
@Override
protected Connection initialValue() {
Connection conn = null;
try {
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test", "username",
"password");
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}; public static Connection getConnection() {
return connectionHolder.get();
} public static void setConnection(Connection conn) {
connectionHolder.set(conn);
}
}
1、ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候
线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,
如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断
如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情
ReentrantLock获取锁定与三种方式:
a) lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
c)tryLock(long timeout,TimeUnit unit), 如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
d) lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断
2、synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异
常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到
finally{}中
3、在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;
下面内容 是转载 http://zzhonghe.iteye.com/blog/826162
5.0的多线程任务包对于同步的性能方面有了很大的改进,在原有synchronized关键字的基础上,又增加了ReentrantLock,以及各种Atomic类。了解其性能的优劣程度,有助与我们在特定的情形下做出正确的选择。
总体的结论先摆出来:
synchronized:
在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。
ReentrantLock:
ReentrantLock
提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞
争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而
ReentrantLock确还能维持常态。
Atomic:
和上面的类似,不激烈情况下,性能比synchronized略
逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一
段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。
所以,我们写同步的时候,优先考虑synchronized,如果有特殊需要,再进一步优化。ReentrantLock和Atomic如果用的不好,不仅不能提高性能,还可能带来灾难。
Java同步学习(持续更新)的更多相关文章
- MongoDB学习——持续更新
參考MongoDB权威指南,学习阶段.大家多多交流问题.持续更新本文 MongoDB的长处 MongoDB具有丰富的数据模型,是面向文档的数据库. easy扩展.能够在多台server之间切割数据. ...
- Java名词术语---持续更新
在看技术文档的过程中,经常会出现新的java缩写术语,很多时候都不知道它们是什么,在这里记下,持续更新. ——————————————————————————————————————————————— ...
- 2019春招面试高频题(Java版),持续更新(答案来自互联网)
第一模块--并发与多线程 Java多线程方法: 实现Runnable接口, 继承thread类, 使用线程池 操作系统层面的进程与线程(对JAVA多线程和高并发有了解吗?) 计算机资源=存储资源+计算 ...
- 常见算法合集[java源码+持续更新中...]
一.引子 本文搜集从各种资源上搜集高频面试算法,慢慢填充...每个算法都亲测可运行,原理有注释.Talk is cheap,show me the code! 走你~ 二.常见算法 2.1 判断单向链 ...
- Java基础——集合(持续更新中)
集合框架 Java.util.Collection Collection接口中的共性功能 1,添加 booblean add(Object obj); 往该集合中添加元素,一次添加一个 boolea ...
- 读书笔记|Windows 调试原理学习|持续更新
关于调试方面的学习笔记,主要来源于<软件调试>的读书笔记和梦织未来论坛的视频教程 1.调试器使用一个死循环监听调试信息. DebugActiveProcess(PID);while(TRU ...
- Java笔记(持续更新中)
Java语言的特点: 面向对象(封装,继承,多态) 平台无关性(JVM运行.class文件) 语言(泛型,Lambda) 类库(集合,并发,网络,IO/NIO) JRE(Java运行环境,JVM,类 ...
- java并发编程[持续更新]
目录 java并发编程 1.常用类介绍 Semaphore 2.名词解释 2.1 线程安全 2.2 可重入锁和不可重入锁 java并发编程 1.常用类介绍 Semaphore Semaphore 类是 ...
- Java基础——多线程(持续更新中)
如何建立一个执行路径呢? 通过查询API文档 java.lang.Thread类 该类的描述中有创建线程的两种方式 1.继承Thread类 (1).将类声明为 Thread 的子类 (2).该子类应重 ...
随机推荐
- idea启动springboot项目 报错:java.lang.NoSuchMethodError: javax.servlet.ServletContext.getClassLoader()Ljava/lang/ClassLoader;
有一次启动springboot项目的时候,报了一个非常奇怪的错误,说是找不到servletContext,springboot不是自带tomcat的吗? 在网上找了好久,说是用以下方式解决. 解决方式 ...
- 正则表达式中pw、IDCard和EM匹配
1密码强度正则 //密码强度正则,最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符 var pPattern = /^.*(?=.{6,})(?=.*\d)(?=.*[A-Z])( ...
- 云服务器上mysql的配置
mysql的配置 要想云服务器的mysql数据库能被外部连接,还需要做一些配置 首先执行下面三条命令: sudo apt-get install mysql-server sudo apt isnta ...
- Lua 语言环境安装
Linux 系统上安装(本文使用了5..0版本进行安装:) curl -R -O http://www.lua.org/ftp/lua-.tar.gz tar zxf lua-.tar.gz cd l ...
- zabbix3.4.7Web页面监控
1. 新增Web monitoring 2. 新增一个触发器Trigger 点击“Insert”以后,完成后点击页面下的Add之后,可以看见如下 3. 测试-检测告警效果 接下来,我在Nginx上将i ...
- 操作系统介绍-操作系统历史,IO,进程的三态,同步异步阻塞非阻塞
1.操作系统历史 2.进程,IO,同步异步阻塞非阻塞 操作系统历史: 手工操作: 1946年第一台计算机诞生--20世纪50年代中期,计算机工作还在采用手工操作方式.此时还没有操作系统的概念. 手工操 ...
- MapServer Tutorial——MapServer7.2.1教程学习——第一节:MapServer的基本配置管理,静态地图应用以及MapFile文件
MapServer Tutorial——MapServer7.2.1教程学习——第一节:MapServer的基本配置管理,静态地图应用以及MapFile文件 前言 万事开头难,有了<MapSer ...
- mysql sql文件批量处理
简单动作复杂化,导致处理文件误入坑, 数据库拷贝,备份还原是每个面向对象的开发人员避免不了的动作,在数据库使用中,习惯性的使用第三方数据库管理软件,最近需要做数据库迁移,导出的批量sql文件不知如何区 ...
- oracle中 trunc 处理日期的用法
方法/步骤 1 select trunc(sysdate) from dual 结果是 截止到当日 不设置,默认是截止到”日“ 2 select trunc(sysdate,'year') fr ...
- 何在mysql查找效率慢的SQL语句?
如何在mysql查找效率慢的SQL语句呢?这可能是困然很多人的一个问题,MySQL通过慢查询日志定位那些执行效率较低的SQL 语句,用--log-slow-queries[=file_name]选项启 ...