1、Java 中为了实现线程间互斥的效果,除了使用synchronized关键字外,还可以使用Lock对象去实现
public class LockTest
{
//实例化Outputer对象
static Outputer outputer = new Outputer();
public static void main(String[] args)
{
//线程1
Thread t1 = new Thread(new Runnable()
{
@Override
public void run()
{
while(true)
{
//调用outputer对象的output
outputer.output("abcdefghijk");
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
});
//线程2
Thread t2 = new Thread(new Runnable()
{
@Override
public void run()
{
while(true)
{
//调用outputer对象的output
outputer.output("mnopqrstuvw");
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
});
t1.start();
t2.start();
}
}
class Outputer
{
//生成当前对象的线程锁
Lock lock = new ReentrantLock();
public void output(String str)
{
lock.lock();
try
{
int len = str.length();
for(int i = 0; i < len; i++)
{
System.out.print(str.charAt(i));
}
System.out.println();
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
//释放对象锁
lock.unlock();
}
}
}
使用lock或者是synchronized关键字,如果当前对象的锁,被其他线程获取,当前线程将无法执行被锁定的代码,那么如何实现 “执行读取操作不需要线程间互斥,仅写入操作才实现互斥”
2、Java中的ReadWriteLock对象的使用
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLockTest
{
public static void main(String[] args)
{
final MyQueue queue = new MyQueue();
for(int i = 0; i < 3; i++)
{
new Thread(new Runnable()
{
@Override
public void run()
{
while (true)
{
queue.get();
}
}
}).start();
}
for(int i = 0; i < 3; i++)
{
new Thread(new Runnable()
{
@Override
public void run()
{
while (true)
{
queue.set(new Random().nextInt(10000));
}
}
}).start();
}
}
}
class MyQueue
{
/*
* 共享数据
* 只能有一个线程对此数据执行写操作
* 可以有多个线程对此线程执行读操作
*/
private Object data = null;
//读写锁
private ReadWriteLock lock = new ReentrantReadWriteLock();
public void get()
{
//lock
lock.readLock().lock();
try
{
System.out.println(Thread.currentThread().getName()
+ " 准备读取数据!");
Thread.sleep((long)new Random().nextInt(1000));
System.out.println(Thread.currentThread().getName() +
" 数据读取完成 data = " + data);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
//unlock
lock.readLock().unlock();
}
}
public void set(Object data)
{
//lock
lock.writeLock().lock();
try
{
System.out.println(Thread.currentThread().getName()
+ " 准备写入数据!");
Thread.sleep((long)new Random().nextInt(1000));
this.data = data;
System.out.println(Thread.currentThread().getName()
+ " 写入数据完成 data = " + data);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
finally
{
//lock
lock.writeLock().unlock();
}
}
}
关于ReadWriteLocak对象实现读写锁的面试题:写出一份缓存系统的伪代码
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class CacheDemo
{
//cacheMap用于保存已经获取的对象数据
private Map<String, Object> cacheMap =
new HashMap<String, Object>();
//读写锁
private ReadWriteLock lock = new ReentrantReadWriteLock();
/**
* 获取数据
* @param key
* @return Object
*/
public Object getData(String key)
{
/*
* 读取数据锁 上锁
* 是为了保证多个线程读取数据的时,不会产生空数据
*/
lock.readLock().lock();
Object obj = null;
try
{
//从缓存区中获取数据
obj = cacheMap.get(key);
//判断是否存在数据 如果不存在数据则创建新数据
if(obj == null)
{
//释放读取数据锁 P1
lock.readLock().unlock();
//获取写数据锁 P2
lock.writeLock().lock();
/*
* 由于读数据锁可以多个线程同时读取
* 因为可能有多个线程处于P1位置或者出去P2等待写锁的位置
* 为了避免多次执行写操作
* 所以在获得写锁后 再次判断是否为空
*/
if(obj == null || cacheMap.get(key) == null)
{
try
{
//创建新的数据
obj = new Object();
//将数据放入缓存区中
cacheMap.put(key, obj);
}
catch (Exception e)
{
e.printStackTrace();
}
}
//获取读取锁
lock.readLock().lock();
//释放写数据锁
lock.writeLock().unlock();
}
}
catch (Exception e)
{
e.printStackTrace();
}
//释放读取数据锁
lock.readLock().unlock();
return obj;
}
}