多线程、并发

来源:互联网 发布:百度百家号收益算法 编辑:程序博客网 时间: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;}}


0 0
原创粉丝点击