数据库-事务

安全隐患

读:

脏读 (一个事务读到了另一个事务未提交的数据)

不可重复读(一个事务读到了另一个事务已经提交的数据,造成前后两次查询不一致)

幻读(一个事务读到了另一个事务insert的数据)

写:

丢失更新(两者首先读到同样的数据,但是后面更改的数据覆盖了前面的更改)

解决方法

1.悲观锁

依靠数据库的锁机制实现

select * from account for update;(数据库锁机制,排他锁)

例如:行锁,表锁,读锁,写锁等,都是在操作之前就上锁。Java中synchronized和reentrantLock等独占锁也是悲观锁思想的体现。

缺点:数据库性能的大量开销(特别对于长事务)

2.乐观锁

方法:版本号机制、CAS算法

版本号机制:在数据表中加上version字段,表示数据被修改的次数,修改一次,加1.当事务A更改数据时,当开始读取到的版本号与数据库当前版本号相同时才更新,否则重新更新。

CAS算法(非阻塞同步):

需要读写的内存值V  进行比较的值A  拟写入的新值B 

场景:适用于多读的应用类型,如数据库的write_condition机制,java中java.util.concurrent.atomic包下的原子变量类(CAS)

缺点:ABA问题

 

隔离级别

读未提交:  脏读

读已提交:  不可重复读

可重复读 : 解决脏读,不可重复读,不能解决幻读(mysql默认

可串行化:解决以上

 

JUC

volatile关键字

内存可见性问题:当多个线程操作共享数据时,彼此不可见。

作用:当多个线程操作共享数据时,可以保证内存中的数据可见。

相较于synchronized是一种较为轻量级的同步策略

区别

1.volatile 不具备互斥性  多个线程都可以访问共享数据(数据在主存中)

2.volatile 不能保证变量的原子性

在什么情况下volatile能够保证线程安全 ?

1.运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值。

2.变量不需要与其他状态变量共同参与不变约束。????????????

应用场景:单例模式

 

原子性:

原子变量 java.util.concurrent.atomic包下提供了常用的原子变量

  1.volatile修饰,保证了内存可见性

  2.CAS算法保证了数据的原子性

    cas算法是硬件对于并发操作共享数据的支持

CAS

1.操作数:内存值V  预估值A  更新值B :只有V==A时,V=B,否则不做任何操作。

2.比同步锁的效率高很多,因为一次尝试失败后,不会放弃cpu资源,而是继续尝试。

3.缺点:手写代码较多。

4.使用方法:

  private AtomicInteger s=new AtomicInteger();

      s.compareAndSet();

 

 

 concurrentHashMap

锁分段机制(并行+效率高)

是一个线程安全的哈希表,采用锁分段代替hashtable的独占锁,提高性能。

concurrentLevel:分段级别(默认16)

 

jdk1.8以后?????????????????

 

当期望许多线程访问一个给定的collection时:

  concuerrenthashmap 优于 hashmap

  concurrentskiplistmap 优于 treemap

  copyonWriteArraylist (写入并复制)   优于  arraylist

 CountDownLatch闭锁

 在完成某些运算时,只有其他所有线程的运算全部完成,当前运算才会继续执行。

 对线程进行控制,例如,对多个线程任务进行计时。

latch.countDown();每运行完1,减1;

latch.await(); 等到所有线程运算结束,再进行总运算,如电商中不同种类商品销量总统计。

 

创建多线程的方式3

实现callable接口(可以有返回值,并可以抛出异常)

class threadDemo implements Callable<Integer>{

     public Integer call()  throws Exception{

}

}

执行callable,需要futureTask实现类支持。

 

lock同步锁

解决多线程安全的方法:同步代码块,同步方法,同步锁 lock(显式锁)

方法:通过lock()方法上锁,再通过unlock方法进行释放锁(放在finally)。

 

等待唤醒机制

生产消费者案例

 

线程池

作用:提供了一个线程,队列中保存着所有等待状态的线程,避免了创建与销毁的额外开销,提供响应速度。

体系结构

java.util.concurrent.Executor 负责线程的使用与调度的根接口

  ExecutorService 子接口:线程池的主要接口

    ThreadPoolExecutor 线程池的实现类

    ScheduledExecutorService 子接口:负责线程的调度的子接口

      ScheduledThreadPoolExecutor 实现类:继承ThreadPoolExecutor ,实现ScheduledExecutorService 

forkJoinPool分支合并框架

大任务分解为小任务,再将结果进行合并。

工作窃取模式:

 

java线程的状态

 

 sleep和wait的区别

1.sleep方法正在执行的线程主动让出CPU资源,在sleep指定时间后cou再回到该线程下继续往下执行,但是并不会释放同步资源锁;

而wait方法是当前线程让自己暂时退出出同步资源锁,只有调用了notify方法,才能让调用了wait方法的线程去参与竞争同步资源锁。

 2.sleep方法可以在任何地方使用,而wait方法只能在同步方法或者同步块中使用。

3.sleep是线程类Thread的方法,到时间自动恢复;而wait是object方法,放弃对象锁,进入等待队列。

 

posted @ 2019-07-08 16:34  hhhl  阅读(176)  评论(0)    收藏  举报