多线程、并发
来源:互联网 发布:百度百家号收益算法 编辑:程序博客网 时间:2024/05/17 05:01
同步分为类级别和对象级别,对应类锁和对象锁。类锁一个类只有一个,static方法被synchronized时需要获得类锁。
同步块和同步方法?
同步方法会锁住整个对象,同步块不会。
sleep()/wait():sleep是Thread类的方法,是个静态方法,所以只对当前线程有效;wait是Object类的方法,调用wait前需要获得对象锁,调用wait后释放对象锁,当wait被notify唤醒后,需要再次获得对象锁以继续执行;若有多个线程wait,notify只会唤醒一个线程,由jvm决定哪个,notifyAll会唤醒所有wait的线程(wait/notify和锁有关,所以必须和symchronized一起使用,必须写在synchronized(obj) {}代码段内)。
Object类中的wait,notify,notifyAll方法用于线程间通信关于资源的锁的状态。
死锁:多个线程无限阻塞,互相等待所需资源。
ThreadLocal:线程级别的局部变量。必须初始化,否则为null。
private static ThreadLocal<Integer> numberContainer = new ThreadLocal<Integer>() { @Override protected Integer initialValue() {return 0;}};
numberContainer.get()/set(Integer i)/remove();
原子操作?
i++不是原子操作,可能会线程不安全
java.util.concurrent.atomic提供了int和long类型的原子封装类,可以原子操作不需要同步。
并发容器?
java的集合类是快速失败的,集合被并发访问并发生冲突时会抛出ConcurrentModificationException
并发容器支持并发的遍历和更新
CocurrentHashMap
ConcurrentHashMap如何实现线程安全?
它把hash表分成很短Segment,每个segment有自己的锁。只要多个操作发生在不同的段上,就可以并发进行。支持完全并发的读,和部分并发的写
put()和get()都是通过key的hash值获取位置,获得链表entry后通过key获得value *因此重写key的equals方法也得重写hashcode方法
size()方法:不加锁size两次,若结果相同返回,否则对每个segment都加锁再size
CopyOnWriteArrayList
CopyOnWriteArraySet
java.util.concurrent
Executor 线程任务的执行者;接口,只有一个execute(Runnable command)方法
ExecutorService 线程池管理者;继承Executor,submit方法对execute方法进行了扩展
ScheduledExecutorService 继承ExecutorService,可延迟执行或定期执行任务
Executors
newCachedThreadPool 可设置线程回收时间,默认60秒
newFixedThreadPool
Callable 类似Runnable,但可以返回对象或抛出异常,在线程池提交Callable任务后返回Future对象,调用Future.get()等待Callable结束并获取返回对象。
BlockingQueue
ArrayBlockingQueue
固定长度创建;只有插入取出用同一个锁(ReenTrantLock实现);数组实现,读快插慢
LinkedBlockingQueue
创建时可不设长度,默认MAX; 插入多和取出锁分开;链表实现,读慢插快
CountDownLatch
CountDownLatch threadSignal = new CountDownLatch(5);
threadSignal.countdown()/await();
给CountDownLatch的实例一个初始值,每执行完一个线程countdown一次,await等待CountDownLatch的实例减到0在执行后面的代码,可以保证多个线程同时结束。
java.util.concurrent.locks
ReenTrantLock 重入锁
激烈争用下性能更佳
Lock lock = new ReenTrantLock(true/false); // true: 按序排队 false:允许插队
lock.lock();
try {
...
} finally {
lock.unlock();
}
java.util.concurrent.atomic
线程安全的基本类型封装类
package com.travelzen.etermface.client.data;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.concurrent.Callable;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import com.travelzen.etermface.common.utils.HttpClientUtil;import com.travelzen.framework.config.tops.TopsConfEnum.ConfScope;import com.travelzen.framework.config.tops.TopsConfReader;import com.travelzen.framework.core.json.JsonUtil;import com.travelzen.rosetta.eterm.common.pojo.EtermRtktResponse;/** * Eterm RTKT 出票后预览票面 * <p> * 远程服务提供方: * <p> * op:http://192.168.160.183:8080 * <p> * op3:http://192.168.161.87:8880 * <p> * beta:http://eterm.if.beta.tdxinfo.com * <p> * product:http://eterm.if.tdxinfo.com * <p> * @author yiming.yan * @Date Mar 2, 2016 */public class EtermRtktClient {private static final Logger LOGGER = LoggerFactory.getLogger(EtermRtktClient.class);private static final String ETERM_SERVER_ADDRESS = "tz-eterm-interface-client/eterm-server-address.properties";private static String prefixUrl = null;private static ExecutorService threadPool = null;static {prefixUrl = TopsConfReader.getConfContent(ETERM_SERVER_ADDRESS, "url", ConfScope.R);// 允许最大线程数根据配置数量调整threadPool = Executors.newFixedThreadPool(2);}/** * Eterm RTKT 出票后预览票面 * <p> * @param officeId * @param isDomestic * @param tktPacks * @return */public static List<EtermRtktResponse> rtkt(String office, boolean isDomestic, List<List<String>> tktPacks) {LOGGER.info("Eterm RTKT 打包任务请求 office:{}, isDomestic:{}, tktPacks:{}", office, isDomestic, tktPacks);if (null == prefixUrl) {LOGGER.error("获取 TZ-Eterm server address 失败!");return null;}Map<String, Future<EtermRtktResponse>> futureMap = new HashMap<String, Future<EtermRtktResponse>>();for (List<String> tktPack:tktPacks) {if (tktPack.size() == 0)continue;for (String tktNo:tktPack) {Future<EtermRtktResponse> future = threadPool.submit(new RtktTask(office, isDomestic, tktNo));futureMap.put(tktNo, future);}}List<EtermRtktResponse> responses = new ArrayList<EtermRtktResponse>();PACK_LOOP:for (List<String> tktPack:tktPacks) {if (tktPack.size() == 0) {LOGGER.error("Eterm RTKT 票号组为空!");responses.add(new EtermRtktResponse(false, "Eterm RTKT 票号组为空!"));continue PACK_LOOP;}List<EtermRtktResponse> tmpResponses = new ArrayList<EtermRtktResponse>();for (String tktNo:tktPack) {try {EtermRtktResponse response = futureMap.get(tktNo).get();tmpResponses.add(response);} catch (Exception e) {LOGGER.error("Eterm RTKT 任务执行异常:" + e.getMessage(), e);responses.add(new EtermRtktResponse(false, "Eterm RTKT 任务执行异常!"));continue PACK_LOOP;}}EtermRtktResponse packResponse = mergePackResponses(tmpResponses);if (packResponse.isSuccess()) {String mainTktNo = null;for (int i=0; i<tmpResponses.size(); i++) {if (0 != tmpResponses.get(i).getFare() && 0 != tmpResponses.get(i).getTax()) {mainTktNo = tktPack.get(i);break;}}if (null != mainTktNo)packResponse.setMainTktNo(mainTktNo);}if (packResponse.getFare() == 0 && packResponse.getTax() == 0) {packResponse.setSuccess(false);packResponse.setErrorMsg("Eterm RTKT 价格异常!");}if (tktPack.size() == 1)LOGGER.info("Eterm RTKT 票号:{} 结果:{}", tktPack, packResponse);elseLOGGER.info("Eterm RTKT 连续票号:{} 结果:{}", tktPack, packResponse);responses.add(packResponse);}if (responses.size() != tktPacks.size()) {LOGGER.error("Eterm RTKT 打包任务结果异常!");return null;}LOGGER.info("Eterm RTKT 打包任务结果:{}", responses);return responses;}private static EtermRtktResponse mergePackResponses(List<EtermRtktResponse> tmpResponses) {if (tmpResponses.size() == 1)return tmpResponses.get(0);EtermRtktResponse response = tmpResponses.get(0);if (!response.isSuccess())return new EtermRtktResponse(false, "Eterm RTKT 连续票号的第1个票号解析异常:" + response.getErrorMsg());if (tmpResponses.size() == 1)return response;for (int i = 1; i < tmpResponses.size(); i++) {if (!tmpResponses.get(i).isSuccess())return new EtermRtktResponse(false, "Eterm RTKT 连续票号的第" + (i+1) + "个票号解析异常:" + response.getErrorMsg());response.getFlights().addAll(tmpResponses.get(i).getFlights());}return response;}public static class RtktTask implements Callable<EtermRtktResponse> {private String office;private boolean isDomestic;private String tktNo;public RtktTask(String office, boolean isDomestic, String tktNo) {this.office = office;this.isDomestic = isDomestic;this.tktNo = tktNo;}@Overridepublic EtermRtktResponse call() throws Exception {LOGGER.info("Eterm RTKT 请求 office:{}, isDomestic:{}, tktNo:{}", office, isDomestic, tktNo);String url = prefixUrl + "/tz-eterm-interface-web/rtkt";Map<String, String> params = new HashMap<String, String>();params.put("office", office);params.put("isDomestic", String.valueOf(isDomestic));params.put("tktNo", tktNo);String responseJson = HttpClientUtil.post(url, params, "UTF-8", "UTF-8", 5 * 1000, 120 * 1000); if (null == responseJson) { LOGGER.error("Eterm RTKT 返回结果为空!"); return new EtermRtktResponse(false, "TZ-Eterm 返回结果为空!"); } LOGGER.info("Eterm RTKT 返回Json {}", responseJson); EtermRtktResponse response = null;try {response = (EtermRtktResponse) JsonUtil.fromJson(responseJson, EtermRtktResponse.class);} catch (IOException e) {LOGGER.error("Json反序列化异常:" + e.getMessage(), e); return new EtermRtktResponse(false, "TZ-Eterm 返回结果异常!");}LOGGER.info("Eterm RTKT 返回结果 {}", response);return response;}}
- 多线程并发
- 多线程、并发
- 多线程并发
- 多线程并发
- 并发多线程
- 多线程并发
- 并发多线程
- 多线程/并发
- 多线程、并发
- 多线程并发处理
- 多线程并发带参数
- java处理多线程并发
- 多线程与并发编程
- 多线程(七)并发集合
- JAVA多线程并发
- java处理多线程并发
- 多线程并发服务器编程
- 简单多线程并发操作
- Git命令笔记
- 什么是尽职调查
- java里抽象类用法
- 安卓技术博文
- 送女儿上学的一件小事
- 多线程、并发
- iOS开源项目
- Python 的一些常用方法
- 第1章从零开始
- iOS技术博文
- Java IO输入输出流 笔记
- 移动前端资源教程
- JavaScript中创建对象的几种方式
- Educational Codeforces Round 11 D. Number of Parallelograms 【pair的使用】