java 解决数据同步

最近涉及到一个接口很多的矩阵计算,计算完成后需要获取插入表中新的数据进行计算。部署后因为矩阵计算时间过长有时候会导致后面的数据获取不到报错,最后是加了synchronized代码块进行同步,顺便整理了下其他方法。

1.synchronized
高开销,尽量减少同步内容,通常同步代码块即可。不可被继承,需要重新显示地声明。

1.1同步实例方法
原理:java每个对象都有一个内置锁,当用此关键字修饰方法时,内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。修饰静态方法时将会锁住整个类(静态成员不属于任何一个实例对象,是类成员,所以实际是当前类的class对象锁)

public synchronized void save(){}

1.2同步代码块
原理: 被该关键字修饰的语句块会自动被加上内置锁,从而实现同步 。
其中又可以锁变量,当前实例(this)和class对象。

//变量
public Object synMethod(Object a1) {
    synchronized(a1) {// 操作}
}

//实例对象
synchronized(this) {// 操作}

//class对象
synchronized(AccountingSync.class) {// 操作}
 TIPS:
  如果没有明确的对象做为锁,又希望代码同步:
class Test implements Runnable{
 // 定一个instance。变量长度为0的数组对象是最佳方案。在编译后的字节码中,生成长度为0的byte[]只需要三条操作码 
  private byte[] lock = new byte[0];  
  public void fun_2(){     
    synchronized(lock){// 操作 } 
}

特殊域变量 volatile
该关键字为域变量的访问提供了一种免锁机制,使用该关键字即告诉虚拟机该域可能会被其他线程更新,因此每次使用都要重新计算而不是使用寄存器中的值,这样每个线程访问到的变量值都是一样的,保证了同步。volatile不会提供任何原子操作,不能用来修改final类型的变量,因此不能替代synchronized。
例:private volatile int count = 0;

2.局部变量实现线程同步
ThreadLocal
如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
常用方法:ThreadLocal()创建一个线程本地变量、initialValue()返回此线程局部变量的当前线程的初始值、get()返回当前线程副本中的值、set(T value)将此线程局部变量的当前线程副本值设为value

private static ThreadLocal<Integer> count = new ThreadLocal<Integer>(){
    @Override
    protected Integer initialValue() {
        return 0;
    }
};
//private static ThreadLocal<Integer> count = ThreadLocal.withInitial(() -> 0);  lambda形式
  ThreadLocal 与同步机制都是为了解决多线程中相同变量访问冲突问题。前者空间换时间,后者时间换空间。

3.重入锁
以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的(同一个加锁线程自己调用自己不会发生死锁情况)。
原理:为每个锁关联一个请求计数和一个占有它的线程,当计数为0时认为是未被占有的。线程请求一个未被占有的锁时,jvm将记录锁的占有者并将请求计数器置位1。如果同一个线程再次请求这个锁,计数将递增,每次占用线程退出同步块,计数器递减,直到0锁被释放。synchronized 和reentrantLock都是可重入锁(ReentrantLock 表现为 API 层面的互斥锁(lock() 和 unlock() 方法配合 try/finally 语句块来完成),synchronized 表现为原生语法层面的互斥锁)

在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。ReentrantLock类是可重入、互斥、实现了Lock接口的锁, 它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。(该类需要手动解锁,最主要的特点是可以实现公平锁,即在锁上等待时间最长的线程将获得锁的使用权)

private static final Lock lock = new ReentrantLock(); //默认false 非公平锁
public void addMoney(int money) {
    lock.lock();//上锁
    try{
     // 操作 
    }finally{
        lock.unlock();//解锁
    }
}

公平锁实现:

private static final Lock lock = new ReentrantLock(true);

响应中断:
一个线程获取不到锁,不会一直等待,ReentrantLock会给与一个中断回应。
该类tryLock(Long timeout,TimeUnitunit)可以选择传入时间参数表示等待指定时间返回锁申请的结果 true/false

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值