Java并发包
重入锁:java.util.concurrent.locks.ReentrantLock
特点:
⑴显式加锁,解锁
⑵可以多次加锁,重入锁,但是,解锁次数必须与加锁次数相同;
package com.dong.testThread;
/**
* 重入锁的使用
*
* author:liuD
*/
import java.util.concurrent.locks.ReentrantLock;
public class TestReenterLock implements Runnable{
public static ReentrantLock lock = new ReentrantLock();
public static int i = 0;
public static int j = 0;
@Override
public void run() {
// TODO Auto-generated method stub
for(int k = 0 ;k < 1000 ; k++) {
//重入锁的特点,锁可以定义多个;
lock.lock();
lock.lock();
try{
//System.out.println(i);
i++;
j++;
}finally {
lock.unlock();
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
TestReenterLock tr = new TestReenterLock();
Thread t1 = new Thread(tr);
Thread t2 = new Thread(tr);
t1.start();
t2.start();
//停止当前主线程,让t1线程运行
t1.join();
t2.join();
System.out.println("i = " + i + " j = " + j);
}
}
⑶中断相应:线程可以被中断,即在等待锁的过程中,可以根据需要取消对锁的请求
lockInterruptibly ()方法,可以对中断进行相应的锁申请动作,即在等待锁的过程中,可以响应中断;
package com.dong.testThread;
import java.util.concurrent.locks.ReentrantLock;
/**
* lock.lockInterruptibly()方法,对锁的请求,统一(注意是统一,即只要是同一个锁,在不同的方法中,都可以对锁的请求进行中断)使用lockInterruptibly()方法,可以中断进行响应的锁申请动作,
* 即等地锁的过程中,可以相应中断
*
*程序分析:t1使用资源,设置一个标记,用来表示锁资源正在使用(也可以将共享资源设置为一个方法,例如读方法,和写方法,当在写的过程中,如果有线程想执行读方法,
* 则使用中断,让其中断对锁的请求),当t2发现t1正在使用资源时,边会放弃请求锁对象,t1继续执行; 注意:这个程序在百分之90的情况下都是按照咱们的逻辑
* 运行,但是有一种情况,不会输出t1的执行过程,为什么?因为当线程启动时,随机执行,t1执行完syso后,然后开始执行lock1.lock()方法,这个时候准
* 备获取锁,如果刚好t2中lock1.lockInterruptibly执行,则会释放t1对象的锁;只要t1加锁成功,则t2的lock1.lockInterruptibly()
* 方法将会获取锁,对于正在使用的锁,t2线程会放弃请求锁对象,则t1正常输出;主要还是,这两个对象使用同一个重入锁;
*
* @author liuD
*
*/
public class testLockInterruptibly {
public static ReentrantLock lock1 = new ReentrantLock();
public static volatile boolean status = true;
public static void main(String[] args) {
Thread t1 = new Thread(new Resource());
Thread t2 = new Thread(new Customer());
t1.start();
t2.start();
}
static class Resource implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"已经开始使用设备");
lock1.lock();
try {
for(int i = 0;i<1000;i++) {
System.out.println(Thread.currentThread().getName()+"设备使用中..........................."+i);
}
}finally {
lock1.unlock();
}
}
}
static class Customer implements Runnable{
public void run() {
System.out.println(Thread.currentThread().getName()+"请求使用设备。。。。。");
if(testLockInterruptibly.status == true) {
try {
System.out.println("好的,"+Thread.currentThread().getName()+"去做别的去了");
//取消对锁的请求,
lock1.lockInterruptibly();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
⑷tryLock()方法: 接受两个参数,一个表示等待时间,另一个表示计时单位,只需将往常锁,替换成tryLock()即可;
⑸公平锁:
在大多说情况下,锁的竞争都是不公平的,根据线程的优先级来进行竞争,有可能造成饥饿现象,同时使用wait()方法或者因为多线程情况下,造成的阻塞状况,在对其唤醒的时候,都是从阻塞队列中随机唤醒一个线程,也有可能造成不平共的现象。公平锁则是会按照先后顺序,保证先到的先得,公平锁也可保证不会产生饥饿现象,只要你排队,最终都可以等到资源的,使用Synchronized关键字进行锁控制,产生的锁就是非公平的,我们需要使用重入锁的另一个构造函数: public ReentrantLock(boolean fair);fair为true时,表示锁是公平的,因为公平锁需要维护一个有序队列,所以公平锁的实现成本较高,性能相对低下,默认情况下也是非公平的,如果没有特殊的要求,也不需要使用公平锁.
⑹Condition条件:
在synchronzied关键字中,wait()和notify()方法可让线程等待和唤醒,在ReentrantLock中也有与其搭配的线程等待和唤醒搭档,即Condition实例,利用Condition对象,我们可以让线程在何时的时间等待,或者在某一个特定的时刻得到通知,继续执行;Condition 接口有以下方法:await()方法会是当前线程等待,同时释放当前锁,但其他线程使用signal()或者signalAll()方法是,线程会重新获得 锁并继续执行,(与notfiy()和notifyAll()方法同理)awaitUniterruptibly()方法与await()方法基本相同,但是他不会在等待过程中相应中断;singal()方法用于唤醒一个在等待中的线程。
package com.dong.testThread;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* Condition条件:
*
* @author liuD
*/
public class TestCondition implements Runnable{
public static ReentrantLock lock = new ReentrantLock();
//使用lock.newCondition()可以生成一个与当前重入锁绑定的Condition实例;
public static Condition condition = lock.newCondition();
public static void main(String[] args) throws InterruptedException {
TestCondition to = new TestCondition();
Thread t1 = new Thread(to);
t1.start();
//主线程睡眠2秒
Thread.sleep(2000);
lock.lock();
System.out.println(Thread.currentThread().getName() + " 唤醒进入等待的线程");
////唤醒线程,condition.signal()调用后,这个线程会释放锁,同时也会要求先获得相关的锁(即显式的lock()),在signal()方法后,系统会从当前condition对象的
//等待队列中,唤醒一个线程
condition.signal();
lock.unlock();
}
@Override
public void run() {
try {
lock.lock();
System.out.println(Thread.currentThread().getName()+ " 线程进入等待队列 ");
//使当前线程进入Condition对象的等待队列中;
condition.await();
System.out.println(Thread.currentThread().getName()+ " is going on");
} catch (Exception e) {
// TODO: handle exception
}finally {
}
}
}
⑺读写锁 ReadWriteLock
JDK5中提供的读写分离锁,使得读和写操作的有序性,同时保证数据的一致性,在多线程中,读写锁的约束为:当线程在进行读时,另一个线程也可以进行读,并不会让其阻塞,当一个线程在共享资源中执行写操作时,另一个线程如果想访问该共享资源,会使其阻塞,直到线程的锁释放才可以,只要是涉及写操作,都会造成阻塞;当读操作次数远远大于写操作,则读写锁就可以发挥最大的功效,提升系统的性能。
读写锁的代码比较多,专门作为一篇笔记进行整理
内容参考《高并发程序设计》 葛一鸣 郭超 ,,由衷感谢此书作者为我们提供学习内容