在Java多线程中,可以使用关键字Synchronized实现线程之间互斥。在JDK1.5之后,提供了线程并发库java.util.concurrent用于操作多线程,其中包含了java.util.concurrent.atomic和java.util.concurrent.lock。atomic可以实现数据或变量的原子性操作,而lock可以实现线程互斥,可以实现读写锁,跟Synchronized一样同属于可重入锁,但在使用上比Synchronized更加灵活。
在代码中,可以通过new ReentrantLock()创建一个lock锁,调用lock()实现对代码上锁,调用unlock()可以解锁。当然,为了保证代码运行出现异常时也能解锁,应该把上锁的代码用try包裹起来,并在finally里解锁,具体代码实现如下:
public class Main {
//静态内部类实现线程共享
static class Example{
//创建lock
Lock lock = new ReentrantLock();
public void outPut(String str){
//上锁
lock.lock();
try{
for(int i=0;i<str.length();i++){
System.out.print(str.charAt(i));
}
System.out.print("\n");
}finally {
//解锁
lock.unlock();
}
}
}
public static void main(String[] args) {
final Example example = new Example();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
example.outPut("str1");
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
example.outPut("str2");
}
}
}).start();
}
}
对于lock的读写锁,可以通过new ReentrantReadWriteLock()获取到一个读写锁。所谓读写锁,便是多线程之间读不互斥,读写互斥。读写锁是一种自旋锁,如果当前没有读者,也没有写者,那么写者可以立刻获得锁,否则它必须自旋在那里,直到没有任何写者或读者。如果当前没有写者,那么读者可以立即获得该读写锁,否则读者必须自旋在那里,直到写者释放该锁。具体代码实现如下:
public class Main {
//静态内部类实现线程共享
static class Example{
//创建lock
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
//读操作
public void read(){
//获取读锁并上锁
lock.readLock().lock();
try{
System.out.println("读线程开始");
Thread.sleep(1000);
System.out.println("读线程结束");
}catch (Exception e){
e.printStackTrace();
}finally{
//解锁
lock.readLock().unlock();
}
}
//写操作
public void write(){
//获取写锁并上锁
lock.writeLock().lock();
try{
System.out.println("写线程开始");
Thread.sleep(1000);
System.out.println("写线程结束");
}catch (Exception e){
e.printStackTrace();
}finally {
//解锁
lock.writeLock().unlock();
}
}
}
public static void main(String[] args) {
final Example example = new Example();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
example.read();
example.write();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
example.read();
example.write();
}
}
}).start();
}
}
运行结果:
根据结果可以发现,多线程下ReentrantReadWriteLock可以多线程同时读,但写的话同一时刻只有一个线程执行。
最后说一说读写锁的应用场景,我们可以利用读写锁可是实现一个多线程下数据缓存的功能,具体实现思路如下:
class dataCatch{
Object data; //缓存的数据
public volatile Boolean isCatch = false; //是否有缓存
ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); //生成读写锁
public void process(){
lock.readLock().lock(); //先加读锁,此时数据不会被修改
//数据没有缓存
if(!isCatch){
lock.readLock().unlock(); //解读锁
lock.writeLock().lock(); //加写锁,此时数据不会被读到
/********
*
* 执行数据查询操作并赋值给data
*
********/
isCatch = true;
lock.readLock().lock(); //先加读锁后解写锁
lock.writeLock().lock();
}
/********
*
* 放回data数据给用户
*
********/
lock.readLock().unlock(); //解读锁
}
}