线程协作
- Thread/Executor/Fork-Join
– 线程启动,运行,结束
– 线程之间缺少协作 - synchronized 同步
– 限定只有一个线程才能进入关键区
– 简单粗暴,性能损失有点大
如何做到线程之间的协作,比如1号线程与2号线程在执行到某一个地方的时候,要会合一下
Lock
- Lock也可以实现同步的效果
– 实现更复杂的临界区结构
– tryLock方法可以预判是否空闲
– 允许分离读写的操作,多个读,一个写
– 性能更好 - ReentrantLock类,可重入的互斥锁
- ReentrantReadWriteLock类,可重入的读写锁
- lock和unlock函数
Lock是synchronized的升级版,synchronized能实现的功能,Lock也都能实现,它可以实现更复杂的协作
ReentrantLock可重入互斥锁示例:
package com.torey;
import java.util.concurrent.locks.ReentrantLock;
public class BuyMilkTeaTest {
private static final ReentrantLock queueLock=new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
buyMilkTea();
}
public static void buyMilkTea() throws InterruptedException {
BuyMilkTeaTest lockExample=new BuyMilkTeaTest();
int STUDENTS_CNT=10;
Thread[] students = new Thread[STUDENTS_CNT];
for (int i = 0; i < STUDENTS_CNT; i++) {
students[i]=new Thread(new Runnable() {
@Override
public void run() {
long walkingTime= (long)(Math.random()*1000);
try {
Thread.sleep(walkingTime);
lockExample.tryToBuyMilkTea();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
});
students[i].start();
}
for (int i = 0; i < STUDENTS_CNT; i++) {
students[i].join();
}
}
public void tryToBuyMilkTea() throws InterruptedException {
boolean flag=true;
while (flag) {
if (queueLock.tryLock()) {
long thinkingTime = (long) (Math.random() * 500);
Thread.sleep(thinkingTime);
System.out.println(Thread.currentThread().getName() + ":来一杯奶茶,排队需要"+thinkingTime+"毫秒");
flag=false;
queueLock.unlock();
}else {
System.out.println(Thread.currentThread().getName() + ": 再等等");
}
if (flag) {
Thread.sleep(2000);
}
}
}
}
ReentrantReadWriteLock可重入互斥锁示例:
package com.torey;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class LockExample {
private static final ReentrantReadWriteLock orderLock=new ReentrantReadWriteLock();
public static void main(String[] args) throws InterruptedException {
handleOrder();
}
public void addOrder() throws InterruptedException {
orderLock.writeLock().lock();
long writingTime= (long) (Math.random()*1000);
Thread.sleep(writingTime);
System.out.println(Thread.currentThread().getName()+"老板:新加一笔订单");
orderLock.writeLock().unlock();
}
public void viewOrder() throws InterruptedException {
orderLock.readLock().lock();
long readingTime= (long)(Math.random()*500);
Thread.sleep(readingTime);
System.out.println(Thread.currentThread().getName() + ": 查看订单本");
orderLock.readLock().unlock();
}
public static void handleOrder(){
LockExample lockExample=new LockExample();
Thread boss = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
lockExample.addOrder();
long watingTime= (long)(Math.random()*1000);
Thread.sleep(watingTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
boss.start();
int workerCnt=3;
Thread[] workers = new Thread[workerCnt];
for (int i = 0; i < workerCnt; i++) {
workers[i] = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
lockExample.viewOrder();
long workingTime= (long)(Math.random()*5000);
Thread.sleep(workingTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
workers[i].start();
}
}
}
Semaphore
- 信号量,由1965年Dijkstra提出的
- 信号量:本质上是一个计数器
- 计数器大于0,可以使用,等于0不能使用
- 可以设置多个并发量,例如限制10个访问
- Semaphore有两个重要的方法
– acquire 获取一个信号量,信号量减一
– release 释放一个信号量,信号量加一 - 比Lock更进一步,可以控制多个同时访问关键区
Semaphore示例:
package com.torey;
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
private final Semaphore placeSemaphore=new Semaphore(5);
public boolean parking(){
if (placeSemaphore.tryAcquire()) {
System.out.println(Thread.currentThread().getName() + ": 停车成功");
return true;
}else {
System.out.println(Thread.currentThread().getName() + ":没有空位");
return false;
}
}
public void leaving(){
placeSemaphore.release();
System.out.println(Thread.currentThread().getName() + ": 走开");
}
public static void main(String[] args) throws InterruptedException {
int tryToParkCnt=10;
SemaphoreExample semaphoreExample = new SemaphoreExample();
Thread[] parkers = new Thread[tryToParkCnt];
for (int i = 0; i < tryToParkCnt; i++) {
parkers[i]= new Thread(new Runnable() {
@Override
public void run() {
long randomTime= (long)(Math.random()*1000);
try {
Thread.sleep(randomTime);
if (semaphoreExample.parking()) {
long parkingTime= (long)(Math.random()*1200);
Thread.sleep(parkingTime);
semaphoreExample.leaving();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
parkers[i].start();
}
for (int i = 0; i < tryToParkCnt; i++) {
parkers[i].join();
}
}
}