1.常用工具类
(1)countDownLatch
例子:
public class UseCountDownLatch {
public static void main(String[] args) {
CountDownLatch countDown = new CountDownLatch(2);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("进入线程t1,等待其他线程处理完成...");
countDown.await();
System.out.println("t1线程继续执行");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("t2线程初始化操作...");
Thread.sleep(3000);
System.out.println("t1线程初始化完毕,通知t1线程继续执行...");
countDown.countDown();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}, "t2");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("t3线程初始化操作...");
Thread.sleep(4000);
System.out.println("t3线程初始化完毕,通知t1线程继续执行...");
countDown.countDown();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}, "t2");
t1.start();
t2.start();
t3.start();
}
}
运行结果:
进入线程t1,等待其他线程处理完成…
t3线程初始化操作…
t2线程初始化操作…
t1线程初始化完毕,通知t1线程继续执行…
t3线程初始化完毕,通知t1线程继续执行…
t1线程继续执行
CountDownLatch countDown = new CountDownLatch(2);中的2表示conutdown调用几次,
t2,t3线程调用完之后,t1线程才继续执行
2.cyclicBarrier使用
例子:
public class UseCycliBarrier {
static class Runner implements Runnable{
private CyclicBarrier barrier;
private String name;
public Runner(CyclicBarrier barrier, String name) {
this.barrier = barrier;
this.name = name;
}
@Override
public void run() {
try {
Thread.sleep(1000*(new Random().nextInt(5)));
System.out.println(name+"准备OK。");
barrier.await();
}catch (Exception e){
e.printStackTrace();
}
System.out.println(name+"GO!!");
}
}
public static void main(String[] args) {
CyclicBarrier ba = new CyclicBarrier(3);
ExecutorService executor = Executors.newFixedThreadPool(3);
executor.submit(new Thread(new Runner(ba,"zhangsan")));
executor.submit(new Thread(new Runner(ba,"lisi")));
executor.submit(new Thread(new Runner(ba,"wangwu")));
executor.shutdown();
}
}
运行结果:
lisi准备OK。
wangwu准备OK。
zhangsan准备OK。
zhangsanGO!!
lisiGO!!
wangwuGO!!
三个线程使用同一个CyclicBarrier ,三个线程都执行完了await之后,再同时一起往下执行。
应用场景:如多台机器同一个点开始去计算的时候。
conutdown针对一个线程,CyclicBarrier 针对多个线程
例子:
public class UseFuture implements Callable<String> {
private String para;
public UseFuture (String para){
this.para=para;
}
/**
* 这里是真实的业务逻辑,其执行可能很慢
* @return
* @throws Exception
*/
@Override
public String call() throws Exception {
//模拟执行耗时
Thread.sleep(3000);
String result=this.para+"处理完成";
return result;
}
public static void main(String[] args) throws Exception {
String queryStr="query";
//构造FutureTask,并且传入需要真正进行业务逻辑处理的类,该类一定是实现了Callable接口的类
FutureTask<String> future = new FutureTask<>(new UseFuture(queryStr));
//创建一个固定线程的线程池且线程数为1
ExecutorService executor = Executors.newFixedThreadPool(1);
//这里提交任务future,则开启线程执行RealData的call()方法执行
//submit和execute的区别:第一点是submit可以传入实现callable接口的实例对象,
//第二点是submit方法有返回值
Future f = executor.submit(future);
//会立马返回null
System.out.println("请求完毕");
System.out.println(f.get());
/*
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}*/
/*while (true){
if(f.get()==null){
System.out.println("当前任务执行完毕");
break;
}
}*/
//可以用 FutureTask<String> 的get去获取值
//如果call方法没有执行完,则依然会进行等待
System.out.println("数据:"+future.get());
executor.shutdown();
}
}
Semaphore又称信号量,是操作系统中的一个概念,在Java并发编程中,信号量控制的是线程并发的数量。
public Semaphore(int permits)
其中参数permits就是允许同时运行的线程数目;
下面先看一个信号量实现单线程的例子,也就是permits=1:
public class Driver {
// 控制线程的数目为1,也就是单线程
private Semaphore semaphore = new Semaphore(1);
public void driveCar() {
try {
// 从信号量中获取一个允许机会
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());
// 释放允许,将占有的信号量归还
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Car extends Thread{
private Driver driver;
public Car(Driver driver) {
super();
this.driver = driver;
}
public void run() {
driver.driveCar();
}
}
public class Run {
public static void main(String[] args) {
Driver driver = new Driver();
for (int i = 0; i < 5; i++) {
(new Car(driver)).start();
}
}
}
输出结果:
Thread-0 start at 1546858676423
Thread-0 stop at 1546858677424
Thread-1 start at 1546858677424
Thread-1 stop at 1546858678424
Thread-2 start at 1546858678424
Thread-2 stop at 1546858679424
Thread-3 start at 1546858679424
Thread-3 stop at 1546858680425
Thread-4 start at 1546858680425
Thread-4 stop at 1546858681425
将信号量设为3,线程总数设为10
输出结果:
Thread-1 start at 1546858780808
Thread-2 start at 1546858780808
Thread-0 start at 1546858780808
Thread-2 stop at 1546858781808
Thread-0 stop at 1546858781808
Thread-1 stop at 1546858781808
Thread-4 start at 1546858781808
Thread-3 start at 1546858781808
Thread-6 start at 1546858781808
Thread-6 stop at 1546858782809
Thread-3 stop at 1546858782809
Thread-4 stop at 1546858782809
Thread-8 start at 1546858782809
Thread-5 start at 1546858782809
Thread-7 start at 1546858782809
Thread-8 stop at 1546858783810
Thread-7 stop at 1546858783810
Thread-5 stop at 1546858783810
Thread-9 start at 1546858783810
Thread-9 stop at 1546858784810
从结果上看,发现3个线程同时执行。但第四个线程要等前面有一个完成之后才能执行。
信用量也可以一次获取多个。或者释放多个 如:
semaphore.acquire(3); semaphore.release(3);
参照:https://blog.csdn.net/sinat_36246371/article/details/53872412
例子:
public class UseSemaphore {
public static void main(String[] args) {
//线程池
ExecutorService exec = Executors.newCachedThreadPool();
//只能5个线程同时访问
final Semaphore semp = new Semaphore(5);
//模拟20个客户端访问
for (int index = 0; index < 20; index++) {
final int NO =index;
Runnable run = new Runnable() {
@Override
public void run() {
//获取许可
try {
semp.acquire();
System.out.println("Accessing:"+NO);
//模拟实际业务逻辑
// Thread.sleep((long) (Math.random()*10000));
Thread.sleep(1000);
//访问完后,释放
semp.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
exec.execute(run);
}
try {
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
//退出线程池
exec.shutdown();
}
}
场景:可以模仿最大可连接数,使性能更好的利用
锁
ReentrantLock(重入锁)
读写锁
实例:
public class UseCondition {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void method1(){
try {
lock.lock();
System.out.println("当前线程:" + Thread.currentThread().getName() + "进入等待状态..");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + "释放锁..");
condition.await(); // Object wait
System.out.println("当前线程:" + Thread.currentThread().getName() +"继续执行...");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void method2(){
try {
lock.lock();
System.out.println("当前线程:" + Thread.currentThread().getName() + "进入..");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + "发出唤醒..");
condition.signal(); //Object notify
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
final UseCondition uc = new UseCondition();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
uc.method1();
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
uc.method2();
}
}, "t2");
t1.start();
t2.start();
}
}
public class UseManyCondition {
private ReentrantLock lock = new ReentrantLock();
private Condition c1 = lock.newCondition();
private Condition c2 = lock.newCondition();
public void m1(){
try {
lock.lock();
System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m1等待..");
c1.await();
System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m1继续..");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void m2(){
try {
lock.lock();
System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m2等待..");
c1.await();
System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m2继续..");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void m3(){
try {
lock.lock();
System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m3等待..");
c2.await();
System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m3继续..");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void m4(){
try {
lock.lock();
System.out.println("当前线程:" +Thread.currentThread().getName() + "唤醒..");
c1.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void m5(){
try {
lock.lock();
System.out.println("当前线程:" +Thread.currentThread().getName() + "唤醒..");
c2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
final UseManyCondition umc = new UseManyCondition();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
umc.m1();
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
umc.m2();
}
},"t2");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
umc.m3();
}
},"t3");
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
umc.m4();
}
},"t4");
Thread t5 = new Thread(new Runnable() {
@Override
public void run() {
umc.m5();
}
},"t5");
t1.start(); // c1
t2.start(); // c1
t3.start(); // c2
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t4.start(); // c1
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t5.start(); // c2
}
}
//读写锁
public class UseReentrantReadWriteLock {
private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
private ReadLock readLock = rwLock.readLock();
private WriteLock writeLock = rwLock.writeLock();
public void read(){
try {
readLock.lock();
System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
} catch (Exception e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
}
public void write(){
try {
writeLock.lock();
System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
Thread.sleep(3000);
System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
} catch (Exception e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
}
public static void main(String[] args) {
final UseReentrantReadWriteLock urrw = new UseReentrantReadWriteLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
urrw.read();
}
}, "t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
urrw.read();
}
}, "t2");
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
urrw.write();
}
}, "t3");
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
urrw.write();
}
}, "t4");
// t1.start();
// t2.start();
// t1.start(); // R
// t3.start(); // W
t3.start();
t4.start();
}
}
因为时间问题,后面的请自行百度