Java多线程
重入锁的搭档-Condition
Condition的功能类似于内部锁Synchronized
下的Object.wait()
和Object.notify()
,主要用于可重入锁ReentrantLock
的等待和唤醒
public class ReentrantLockCondition implements Runnable {
private static final ReentrantLock LOCK = new ReentrantLock();
private static final Condition CONDITION = LOCK.newCondition();
@Override
public void run() {
LOCK.lock();
try {
CONDITION.await();
System.out.println(Thread.currentThread().getName() + " end");
} catch (InterruptedException ignore) {
} finally {
// 一定要在finally释放锁!
LOCK.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ReentrantLockCondition reentrantLockCondition = new ReentrantLockCondition();
Thread thread = new Thread(reentrantLockCondition, "my-thread");
thread.start();
Thread.sleep(3000);
// 必须先获得锁,才能调用signalAll等方法
LOCK.lock();
// 唤醒所有等待的线程
CONDITION.signalAll();
// 释放锁,不然虽然唤醒,但是会由于获取不到锁而继续等待
LOCK.unlock();
}
}
信号量
使用信号量可以实现控制多个线程访问一个资源,是锁的一种扩展,例子如下
public class SemapDemo implements Runnable {
/**
* 同时可以有5个线程进入
*/
final Semaphore semp = new Semaphore(5);
@Override
public void run() {
try {
semp.acquire();
Thread.sleep(2000);
System.out.println(Thread.currentThread().getId() + ":done!");
} catch (InterruptedException ignore) {}
finally {
semp.release();
}
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(20);
SemapDemo semapDemo = new SemapDemo();
for (int i = 0; i < 20; i++) {
executorService.submit(semapDemo);
}
executorService.shutdown();
}
}
这里一次只允许5个线程进入代码acquire()
和release()
之间,输出也是5个一组为输出。
读写锁
读写锁适用于读取的情况远大于写入的情况,这时候使用读写锁会大幅度提高性能,这里需要注意的是,在读的时候会阻塞写入,而写入的时候也会阻塞读取,但是读取和读取的线程是不会引起资源竞争的
public class ReadWriteLockDemo {
private static final Lock LOCK = new ReentrantLock();
private static final ReentrantReadWriteLock READ_WRITE_LOCK = new ReentrantReadWriteLock();
private static final Lock READ_LOCK = READ_WRITE_LOCK.readLock();
private static final Lock WRITE_LOCK = READ_WRITE_LOCK.writeLock();
private int value;
public int handleRead() {
try {
READ_LOCK.lock();
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
READ_LOCK.unlock();
}
return value;
}
public void handleWrite(int index) {
try {
WRITE_LOCK.lock();
Thread.sleep(1000);
value = index;
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
WRITE_LOCK.unlock();
}
}
public static void main(String[] args) {
ReadWriteLockDemo demo = new ReadWriteLockDemo();
Runnable readRunnable = demo::handleRead;
Runnable writeRunnable = ()->{
demo.handleWrite(new Random().nextInt());
};
for (int i = 0; i < 18; i++) {
new Thread(readRunnable).start();
}
for (int i = 0; i < 2; i++) {
new Thread(writeRunnable).start();
}
}
}
这里开启了18个读线程,在读取的操作上是完全并行的,而接下来的又创建了两个写线程,写会阻塞读的操作。实际代码运行约3秒就能结束。