java怎么设置获取读写锁超时时间
1 package bing.test;
2
3 import java.util.concurrent.locks.Lock;
4 import java.util.concurrent.locks.ReadWriteLock;
5 import java.util.concurrent.locks.ReentrantReadWriteLock;
6
7 public class UpgradeLock{
8 private UpgradeLock(){ }
9 private final static ReadWriteLock rwlock =new ReentrantReadWriteLock();
10 private final static Lock read=rwlock.readLock();
11 private final static Lock write=rwlock.writeLock();
12
13
14 public static void main(String[] args){
15 log(getReadLock());
16 log(getWriteLock());
17 }
18
19
20 public static boolean getReadLock()
21 {
22 try{
23 int time = 0;
24 // 设置超时时间为5秒,获取Lock,
25 //如果返回false(即获取失败)则等待直到超时,然后返回获取lock的状态
26 while(!read.tryLock() ++time 5){
27 Thread.sleep(1000);
28 log(time);
29 }
30 return read.tryLock();
31 }catch(Exception e)
32 {
33 e.printStackTrace();
34 return false;
35 }
36 }
37 public static boolean getWriteLock()
38 {
39 try{
40 int time = 0;
41 // 设置超时时间为5秒,获取Lock,
42 //如果返回false(即获取失败)则等待直到超时,然后返回获取lock的状态
43 while(!write.tryLock() ++time 5){
44 Thread.sleep(1000);
45 log(time);
46 }
47 return read.tryLock();
48 }catch(Exception e)
49 {
50 e.printStackTrace();
51 return false;
52 }
53 }
54 public static void log(Object m){
55 System.out.println(m);
56 }
57 }
java怎样将数据保存到缓存中,之后再保存
Java中可以使用队列来保存数据,当使用的时候,加上锁,防止其他进程访问,当不用的时候保存到数据库里面,示例如下:
package com.henry;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CacheDataTest {
static MapInteger,Object dataMap=new HashMapInteger,Object();
static ReadWriteLock lock=new ReentrantReadWriteLock();//创建读写锁的实例
static Object getData(Integer key){
lock.readLock().lock();//读取前先上锁
Object val=null;
try{
val=dataMap.get(key);
if(val == null){
// Must release read lock before acquiring write lock
lock.readLock().unlock();
lock.writeLock().lock();
try{
//可能已经由其他线程写入数据
if(val==null){
//dataMap.put(key, “”);//query from db
val=queryDataFromDB(key);
}
}finally{
//Downgrade by acquiring read lock before releasing write lock
lock.readLock().lock();
// Unlock write, still hold read
lock.writeLock().unlock();
}
}
}finally{
lock.readLock().unlock();//最后一定不要忘记释放锁
}
System.out.println(“get data key=”+key+”val=”+val);
return val;
}
static Object queryDataFromDB(Integer key){
Object val=new Random().nextInt(1000);
dataMap.put(key, val);
System.out.println(“write into data key=”+key+”val=”+val);
return val;
}
public static void main(String[] args) {
for(int i=0;i10;i++){
new Thread(new Runnable(){public void run() {
getData(new Random().nextInt(5));
}}).start();
}
}
}
java readwritelock读写分离吗
读写锁 ReadWriteLock读写锁维护了一对相关的锁,一个用于只读操作,一个用于写入操作。只要没有writer,读取锁可以由多个reader线程同时保持。写入锁是独占的。
互斥锁一次只允许一个线程访问共享数据,哪怕进行的是只读操作;读写锁允许对共享数据进行更高级别的并发访问:对于写操作,一次只有一个线程(write线程)可以修改共享数据,对于读操作,允许任意数量的线程同时进行读取。
与互斥锁相比,使用读写锁能否提升性能则取决于读写操作期间读取数据相对于修改数据的频率,以及数据的争用——即在同一时间试图对该数据执行读取或写入操作的线程数。
读写锁适用于读多写少的情况。
可重入读写锁 ReentrantReadWriteLock
属性ReentrantReadWriteLock 也是基于 AbstractQueuedSynchronizer 实现的,它具有下面这些属性(来自Java doc文档):
* 获取顺序:此类不会将读取者优先或写入者优先强加给锁访问的排序。
* 非公平模式(默认):连续竞争的非公平锁可能无限期地推迟一个或多个reader或writer线程,但吞吐量通常要高于公平锁。
* 公平模式:线程利用一个近似到达顺序的策略来争夺进入。当释放当前保持的锁时,可以为等待时间最长的单个writer线程分配写入锁,如果有一组等待时间大于所有正在等待的writer线程的reader,将为该组分配读者锁。
* 试图获得公平写入锁的非重入的线程将会阻塞,除非读取锁和写入锁都自由(这意味着没有等待线程)。
* 重入:此锁允许reader和writer按照 ReentrantLock 的样式重新获取读取锁或写入锁。在写入线程保持的所有写入锁都已经释放后,才允许重入reader使用读取锁。
writer可以获取读取锁,但reader不能获取写入锁。
* 锁降级:重入还允许从写入锁降级为读取锁,实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。但是,从读取锁升级到写入锁是不可能的。
* 锁获取的中断:读取锁和写入锁都支持锁获取期间的中断。
* Condition 支持:写入锁提供了一个 Condition 实现,对于写入锁来说,该实现的行为与 ReentrantLock.newCondition() 提供的Condition 实现对 ReentrantLock 所做的行为相同。当然,此 Condition 只能用于写入锁。
读取锁不支持 Condition,readLock().newCondition() 会抛出 UnsupportedOperationException。
* 监测:此类支持一些确定是读取锁还是写入锁的方法。这些方法设计用于监视系统状态,而不是同步控制。
实现AQS 回顾在之前的文章已经提到,AQS以单个 int 类型的原子变量来表示其状态,定义了4个抽象方法( tryAcquire(int)、tryRelease(int)、tryAcquireShared(int)、tryReleaseShared(int),前两个方法用于独占/排他模式,后两个用于共享模式 )留给子类实现,用于自定义同步器的行为以实现特定的功能。
对于 ReentrantLock,它是可重入的独占锁,内部的 Sync 类实现了 tryAcquire(int)、tryRelease(int) 方法,并用状态的值来表示重入次数,加锁或重入锁时状态加 1,释放锁时状态减 1,状态值等于 0 表示锁空闲。
对于 CountDownLatch,它是一个关卡,在条件满足前阻塞所有等待线程,条件满足后允许所有线程通过。内部类 Sync 把状态初始化为大于 0 的某个值,当状态大于 0 时所有wait线程阻塞,每调用一次 countDown 方法就把状态值减 1,减为 0 时允许所有线程通过。利用了AQS的共享模式。
现在,要用AQS来实现 ReentrantReadWriteLock。
一点思考问题
* AQS只有一个状态,那么如何表示 多个读锁 与 单个写锁 呢?
* ReentrantLock 里,状态值表示重入计数,现在如何在AQS里表示每个读锁、写锁的重入次数呢?
* 如何实现读锁、写锁的公平性呢?
一点提示
* 一个状态是没法既表示读锁,又表示写锁的,不够用啊,那就办成两份用了,客家话说一个饭粒咬成两半吃,状态的高位部分表示读锁,低位表示写锁,由于写锁只有一个,所以写锁的重入计数也解决了,这也会导致写锁可重入的次数减小。
* 由于读锁可以同时有多个,肯定不能再用办成两份用的方法来处理了,但我们有 ThreadLocal,可以把线程重入读锁的次数作为值存在 ThreadLocal 里。
* 对于公平性的实现,可以通过AQS的等待队列和它的抽象方法来控制,在状态值的另一半里存储当前持有读锁的线程数。如果读线程申请读锁,当前写锁重入次数不为 0 时,则等待,否则可以马上分配;如果是写线程申请写锁,当前状态为 0 则可以马上分配,否则等待。
java中读锁的作用,为什么要用读锁
读写锁:ReentrantReadWriteLock
如果有很多线程从一个数据结构中读取数据,而很少的线程修改数据,那么就用读写锁。
分别得到读锁和写锁:
ReentrantReadWriteLock rrwl=new ReentrantReadWriteLock();
ReadLock readL = rrwl.readLock();
WriteLock writeL = rrwl.writeLock();
读锁与读锁不互斥,读锁与写锁互斥,写锁与写锁互斥。
用于优化性能,提高读写速度。
java程序中如何实现对mysql数据库中表的锁定
方法1:用mysql命令锁住表.
public void test() {
String sql = “lock tables aa1 write”;
// 或String sql = “lock tables aa1 read”;
// 如果想锁多个表 lock tables aa1 read ,aa2 write , …..
String sql1 = “select * from aa1 “;
String sql2 = “unlock tables”;
try {
this.pstmt = conn.prepareStatement(sql);
this.pstmt1 = conn.prepareStatement(sql1);
this.pstmt2 = conn.prepareStatement(sql2);
pstmt.executeQuery();
pstmt1.executeQuery();
pstmt2.executeQuery();
} catch (Exception e) {
System.out.println(“异常” + e.getMessage());
}
}
对于read lock 和 write lock官方说明:
1.如果一个线程获得一个表的READ锁定,该线程(和所有其它线程)只能从该表中读取。
如果一个线程获得一个表的WRITE锁定,只有保持锁定的线程可以对表进行写入。
其它的线程被阻止,直到锁定被释放时为止。
2.当您使用LOCK TABLES时,您必须锁定您打算在查询中使用的所有的表。
虽然使用LOCKTABLES语句获得的锁定仍然有效,但是您不能访问没有被此语句锁定的任何的表。
同时,您不能在一次查询中多次使用一个已锁定的表——使用别名代替,
在此情况下,您必须分别获得对每个别名的锁定。
对与read lock 和 write lock个人说明:
1.read lock 和 write lock 是线程级(表级别).
2.在同一个会话中加了read lock锁. 只能对这个表进行读操作.对这个表以外的任何表都无法进行增、删、改、查的操作.
但是在不同会话中,只能对加了read lock的表进行读操作.但可以对read lock以外的表进行增、删、改、查的操作.
3.在同一个会话中加了write lock锁.只能对这个表进行读、写操作.对这个表以外的任何表都无法进行增、删、改、查的操作.
但是在不同会话中,无法对加了write lock的表进行读、写操作.但可以对write lock以外的表进行增、删、改、查的操作.
4.如果表中使用了别名.(SELECT * FROM aa1 AS byname_table)
在对aa1加锁时,必须把别名加上去(lock tables aa1 as byname_table read)
在同一个会话中.必须使用别名进行查询.
在不同的会话中.可以不需要使用别名进行查询.
5.在多个会话中可以对同一个表进行lock read操作.但不能在多个会话中对同一个表进行lock write操作(这些锁将等待已锁的表释放自身的线程锁)
如果多个会话对同一个表进行lock read操作.那么在这些会话中,也只能对以锁的表进行读操作.
6.如果要你锁住了一个表,需要嵌套查询.你必须使用别名,并且,要锁定别名.
例如.lock table aa1 read ,aa1 as byname_table read;
select * from aa1 where id in (select * from aa1 as xx where id=2);
7.解锁必须用unlock tables;
另:
在JAVA程序中,要想解锁,需要调用 unlock tables来解锁.
如果没有调用unlock tables.
关闭connection 、程序结束 、调用GC 都能解锁.
方法2:用记录锁锁表.
public void test() {
String sql = “select * from aa1 for update”;
// select * from aa1 lock in share mode;
try {
conn.setAutoCommit(false);
this.pstmt = conn.prepareStatement(sql);
pstmt.executeQuery();
} catch (Exception e) {
System.out.println(“异常” + e.getMessage());
}
}
1.for update 与 lock in share mode 属于行级锁和页级锁
2.for update 排它锁,lock in share mode 共享锁
3.对于记录锁.必须开启事务.
4.行级锁定事实上是索引记录的锁定.只要是用索引扫描的行(或没索引全表扫描的行),都将被锁住.
5.在不同的隔离级别下还会使用next-key locking算法.即所扫描的行之间的“间隙”也会也锁住(在Repeatable read和Serializable隔离级别下有间隙锁).
6.在mysql中共享锁的含义是:在被共享锁锁住的行,即使内容被修改且并没有提交.在另一个会话中依然看到最新修改的信息.
在同一会话中加上了共享锁.可以对这个表以及这个表以外的所有表进行增、删、改、查的操作.
在不同的会话中.可以查到共享锁锁住行的最新消息.但是在Read Uncommitted隔离级别下不能对锁住的表进行删,
改操作.(需要等待锁释放才能操作…)
在Read Committed隔离级别下不能对锁住的表进行删,改操作.(需要等待锁释放才能操作…)
在Repeatable read隔离级别下不能对锁住行进行增、删、改操作.(需要等待锁释放才能操作…)
在Serializable隔离级别下不能对锁住行进行增、删、改操作. (需要等待锁释放才能操作…)
7.在mysql中排他锁的含义是:在被排它锁锁住的行,内容修改并没提交,在另一个会话中不会看到最新修改的信息。
在不同的会话中.可以查到共享锁锁住行的最新消息.但是Read Uncommitted隔离级别下不能对锁住的表进行删,
改操作.(需要等待锁释放才能操作…)
在Read Committed隔离级别下不能对锁住的表进行删,改操作.(需要等待锁释放才能操作…)
在Repeatable read隔离级别下不能对锁住行进行增、删、改操作.(需要等待锁释放才能操作…)
在Serializable隔离级别下不能对锁住行进行增、删、改操作. (需要等待锁释放才能操作…)
8.在同一个会话中的可以叠加多个共享锁和排他锁.在多个会话中,需要等待锁的释放.
9.SQL中的update 与 for update是一样的原理.
10.等待超时的参数设置:innodb_lock_wait_timeout=50 (单位秒).
11.任何可以触发事务提交的命令,都可以关闭共享锁和排它锁.