关于Java解决线程冲突的方法简单总结
1.在方法面前使用synchronized或者使用方法块
2.使用各种锁lock,Reentrantlock,读写锁
3.使用volatile保证可见性
4.使用ThreadLock复制变量副本
5.java.util.concurrent的API及StringBuffer
解决线程安全问题的各种方法的具体实现
A.Synchronized
synchronized的具体使用方法有两种
1.直接写在方法的修饰符或静态符后面
public synchronized void methodANeedSync(){//同步的代码}
2.在方法内使用synchronized块
public void methodANeedSync(){
synchronized{
//同步的代码
}
}
B.锁
以Reentrantlock的使用为例
在方法外实例化锁
class Demo
{
Lock lock=new Reentrantlock();
void methodANeedLock(){
lock.lock()
try{//需要锁的代码}
catch(Exception e){...}
finall{lock.unlock; //解锁 }
}
}
注意不能让锁变成方法的局部变量,因为每个线程都拥有一个局部变量的副本,会使得获取的锁不一样;
关于读写锁ReadWriteLock
具体实现 ReentrantReadWriteLock
与ReentrantLock的实现基本相同只是上锁和解锁的时候需要注明是读还是写的锁
如:
ReentrantReadWriteLock rrwl=new ReentrantReadWriteLock();
void methodANeedLock(){
rrwls.readlock.lock()
try{//需要锁的代码}
catch(Exception e){...}
finall{rrwl.readlock.jianlock; //解锁 }
}
C.volatile
此关键字修饰的的变量表示这个变量是易变的,不需要编译优化,一旦发生修改即可刷新到主内存中,保证变量的可见性
D.ThreadLocal
可以理解为本地局部变量的意思,对于储存在里面的变量(最好是只有一个变量),使用ThreadLocal.get()方法访问储存在ThreadLocalMap的
变量时,get()方法会判断当前时哪个线程然后基于一个变量副本,就像是一个在方法外部的局部变量一样;
如使用ThreadLcocal实现线程安全的DAO层代码:
public class ThreadLocalDAO {
private static final ThreadLocal<Connection> conLocal=new ThreadLocal<Connection>();
public Connection getCon(){
Connection con=conLocal.get();
if(con==null){
try {
Class.forName("com.mysql.jdbc.Driver");
try {
con= DriverManager.getConnection("#url","#uesr","#password");
} catch (SQLException e) {
e.printStackTrace();
}
conLocal.set(con);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return con;
}
}
E.各种已经封装好且线程安全的集合类或其他API(多数在concurrent包内)
如常用的有:
a.实现BlockingQueue和DequeBlocking接口的所有类
{
ArrayBlockingQueue;
DelayQueue;
LinkedBlockingQueue;
PriorityBlockingQueue;
SynchronousQueue;
LinkedBlockingQueue;
}
b.所有以concurrent开头的集合类 如:concurrentHashMap
c.StringBuffer,Vector,Stack
d.concurrent包内的其他API