目录
- 多线程相关
- CountDownLatch
- 赛跑的案例
- countDownLatch.await(300, TimeUnit.SECONDS);
- Java其他进阶
- Map的put方法
- 只放一个元素的集合
多线程相关
CountDownLatch
案例:主线程的执行需要等待子线程执行完,等各个线程执行完毕后,主线程做收尾的工作
- 初始化一个:final CountDownLatch latch = new CountDownLatch(3);
- 线程池中的子线程调用 countDown方法进行减1;
- 主线程启动后,等待子线程不断减1,直到为0后,主线程继续往下执行;
package com.tianju.myTest;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountdownLatchTest1 {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(3);
final CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
System. out.println("子线程" + Thread.currentThread().getName() + "开始执行");
Thread. sleep((long) (Math. random() * 10000));
System. out.println("子线程" + Thread.currentThread().getName() + "执行完成");
latch.countDown(); // 当前线程调用此方法,则计数减一
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
try {
System. out.println("主线程" + Thread.currentThread().getName() + "等待子线程执行完成..." );
latch.await(); // 阻塞当前线程,直到计时器的值为0
System. out.println("主线程" + Thread.currentThread().getName() + "开始执行...");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
service.shutdown();
}
}
}
赛跑的案例
案例2:4名选手参加赛跑,选手需要等待裁判发送指令;裁判发送完指令后,需要等所有选手到达终点;所有选手到达终点后,裁判汇总成绩。
- 主线程:裁判发指令,裁判等选手到达终点,到达终点后,汇总成绩;
- 子线程:每个选手需要阻塞在裁判发指令之前,主线程发指令后,子线程继续运行;此时主线程阻塞,所有子线程结束后,主线程继续运行
实现的思路
- 定义两个CountDownLatch,一个为1,一个为4;
- CountDownLatch(1),用来控制等待裁判指令,主线程先休眠,让出资源,让子线程获得cpu资源,子线程通过await 阻塞;
- 主线程休眠结束后,对1进行-1,然后await 4 阻塞,触发子线程,子线程继续运行;
- 子线程在运行过程中对于4 进行-1,等到值为0时,触发主线程的await 4 阻塞;
- 主线程继续运行,裁判进行成绩的汇总
package com.tianju.myTest;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
// https://www.cnblogs.com/tstd/p/4987935.html
public class CountdownLatchTest2 {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CountDownLatch cdOrder = new CountDownLatch(1);
final CountDownLatch cdAnswer = new CountDownLatch(4);
for (int i = 0; i < 4; i++) {
Runnable runnable = new Runnable() {
public void run() {
try {
System.out.println("选手" + Thread.currentThread().getName() + "正等待裁判发布口令");
cdOrder.await(); // 线程都阻塞在这里等待释放
System.out.println("选手" + Thread.currentThread().getName() + "已接受裁判口令");
Thread.sleep((long) (Math. random() * 10000));
System.out.println("选手" + Thread.currentThread().getName() + "到达终点");
cdAnswer.countDown(); // 进行-1操作,4个线程都在操作CountDownLatch
System.out.println("cdAnswer---->:"+cdAnswer);
} catch (Exception e) {
e.printStackTrace();
}
}
};
service.execute(runnable);
}
try {
Thread. sleep((long) (Math. random() * 10000));
System. out.println("裁判" + Thread.currentThread ().getName() + "即将发布口令" );
cdOrder.countDown();
System. out.println("裁判" + Thread.currentThread ().getName() + "已发送口令,正在等待所有选手到达终点" );
cdAnswer.await();
System. out.println("所有选手都到达终点" );
System. out.println("裁判" + Thread.currentThread ().getName() + "汇总成绩排名" );
} catch (Exception e) {
e.printStackTrace();
}
service.shutdown();
}
}
countDownLatch.await(300, TimeUnit.SECONDS);
await方法的对比
- 没有设置时间,会一直阻塞,直到countdown为0;
- 设置了时间,在超过这个时间后,解除阻塞,返回false;
线程一直阻塞的情况
到达时间后,就解除阻塞,并返回false
-1成功,返回true
Java其他进阶
Map的put方法
- Map 的 put 方法其实是有返回值的
package com.tianju.myTest;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
/**
* hashMap 的 put 方法其实是有返回值的
*/
public class ConHashMap {
public static void main(String[] args) {
ConcurrentHashMap<Object, Object> concurrentHashMap = new ConcurrentHashMap<>();
// 如果有了键为 pet,还能往里面放
concurrentHashMap.put("pet", 567);
Object put = concurrentHashMap.put("pet", "task");
System.out.println(put);
if (put!=null){
System.out.println("======== current key used! ========");
}
System.out.println(concurrentHashMap);
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put("pet", 123);
Object pet = hashMap.put("pet", 561);
System.out.println(pet);
System.out.println(hashMap);
}
}
只放一个元素的集合
- 基于内存或者业务的考虑,有时候集合只放一个元素,可以用collections下面的singleton集合
package com.tianju.myTest;
import java.util.Collections;
import java.util.List;
/**
* 只能存放一个元素的 List,不会造成内存空间的浪费
*/
public class SingletonListTest {
public static void main(String[] args) {
String s = "hello, singleton";
List<String> list = Collections.singletonList(s);
list.add("second element");
}
}