Lock接口、重入锁
JDK1.5加入,与synchronized相比较,显示、定义、结构更加灵活。即性能更加优越。
常用方法:
void lock() 获取锁,如果锁被占用,则等待。
Boolean Trylock() 尝试获取锁,成功则返回true,锁被占用则等待,不阻塞
Void unlock() 释放锁
在锁之中调用一个锁,ReentrantLock,类似于互斥锁synchronized。
需求说明,将hello\world两个词加入拥有五个位置的数组当中。
代码示例:
MyList类:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Mylist {
private Lock lock=new ReentrantLock();
private String[] str={"A","B","","",""};
private int count=2;
public void add(String value){
lock.lock();
str[count]=value;
//防止进程太快
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public String[] getStr(){
return str;
}
}
MyList的测试类:
import java.util.Arrays;
public class TestMylist {
public static void main(String[] args) throws Exception{
Mylist mylist = new Mylist();
Runnable runnable=new Runnable() {
@Override
public void run() {
mylist.add("hello");
}
};
Runnable runnable2=new Runnable() {
@Override
public void run() {
mylist.add("world");
}
};
Thread t1=new Thread(runnable);
Thread t2=new Thread(runnable2);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(Arrays.toString(mylist.getStr()));
}
}
在锁之中调用一个锁,ReentrantLock,类似于互斥锁synchronized。
卖票案例的ReentrantLock写法:
Ticket类:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Ticket implements Runnable{
private int ticket =100;
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();
try {
if (ticket<0){
break;
}
System.out.println(Thread.currentThread().getName()+"卖了第:"+ticket+"张票");
ticket--;
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
}
对于Ticket的测试类:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestTicket {
public static void main(String[] args) {
Ticket ticket=new Ticket();
ExecutorService es=Executors.newFixedThreadPool(4);
for (int i=0;i<=4;i++){
es.submit(ticket);
}
es.shutdown();
}
}
读写锁
读锁不互斥,写锁互斥。运行效率高
互斥规则:
写-写:互斥,阻塞
读-写:互斥,读阻塞写,写阻塞读
读-读:不互斥,不阻塞
在读操作远远高于写操作的环境中,可在保障线程安全的情况下,提高运行效率。
代码示例:
ReentrantReadWriteLock:
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteDemo {
// 创建读写锁
private ReentrantReadWriteLock rr1 = new ReentrantReadWriteLock();
// 获取读锁
private ReentrantReadWriteLock.ReadLock readLock=rr1.readLock();
// 创建写锁
private ReentrantReadWriteLock.WriteLock writeLock=rr1.writeLock();
private String value;
public String getValue(){
readLock.lock();
try {
try {
// 拿到数据前休眠一会,让程序变慢
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("读取:"+this.value);
return this.value;
} finally {
readLock.unlock();
}
}
public void setValue(String value){
writeLock.lock();
try {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("写入:"+value);
this.value=value;
} finally {
writeLock.unlock();
}
}
}
测试类:
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestReadWriteLock {
public static void main(String[] args) {
ReadWriteDemo readWriteDemo=new ReadWriteDemo();
// 创建线程池
ExecutorService es = Executors.newFixedThreadPool(20);
Runnable read = new Runnable() {
@Override
public void run() {
readWriteDemo.getValue();
}
};
Runnable write = new Runnable() {
@Override
public void run() {
//产生一个1000以内的随机数作为张三的年龄
readWriteDemo.setValue("张三:"+new Random().nextInt(100));
}
};
long start=System.currentTimeMillis();
// 分配18读取任务
for (int i = 0;i < 18;i++){
es.submit(read);
}
for (int j = 0; j < 2;j++ ){
es.submit(write);
}
es.shutdown();//关闭线程
while(!es.isTerminated()){//相当于机器的空转,等待上面的任务全部完成
}
long end = System.currentTimeMillis();
System.out.println("用时="+(end-start));
}
}