前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >血洗多线程,抱得offer归

血洗多线程,抱得offer归

作者头像
xjjdog
发布2019-07-10 10:20:03
4770
发布2019-07-10 10:20:03
举报
文章被收录于专栏:架构专题

许多java开发,都是刚刚接触多线程开发。但即使是有经验的开发,也会陷入很多多线程的陷阱。本篇内容,基本上都是一些反例,有些很低级但常见。当你的程序没有得相应的期望,希望本文能帮你了解到其中的微妙之处。

当然,面试时拿来装逼用,也是极好的。

先来10个。

一、玩命的创建线程池

现象: 系统资源耗尽,进程僵死。 原因: 每次方法执行,都new一个线程池。 作死等级: 五颗星 脑残等级: 五颗星

小姐姐味道解决方式:共用一个线程池即可。

代码语言:javascript
复制
void doJob(){
    ThreadPoolExecutor exe = new ThreadPoolExecutor(...);
    exe.submit(new Runnable(){...})
}
二、锁泄漏

现象: 某个线程一直持有锁而不释放,造成锁泄漏。 原因: 未知异常或逻辑导致unlock函数未执行。 作死等级: 三颗星 脑残等级: 四颗星

小姐姐味道解决方式:始终将unlock函数放在finally中。

代码语言:javascript
复制
private final Lock lock = new ReentrantLock();
void doJob(){
    try{
        lock.lock();
        //do. sth
        lock.unlock();
    }catch(Exception e){
    }
}
三、忘记同步变量

现象: 在某个条件下,抛出 IllegalMonitorStateException。 原因: 调用wait、notify等, 忘记synchronized,或者同步了错误的变量。 作死等级: 两颗星 脑残等级: 四颗星

小姐姐味道解决方式:调用这些函数之前,要使用同步关键字同步它。

代码语言:javascript
复制
Object condition = new Object();

condition.wait();
四、HashMap死循环

现象: cpu占用高,发生死循环,使用jstack查看是阻塞在get方法上。 原因: 在某种条件下,进行rehash时,会形成环形链。某些get请求会走到这个环上。 作死等级: 四颗星 脑残等级: 四颗星

小姐姐味道解决方式:多线程环境下,使用ConcurrentHashMap,别犹豫。

五、给同步的变量重新赋值

现象: 不能够达到同步效果,结果是错误的。 原因: 非基本类型被重新赋值,会改变锁的指向,不同线程持有的锁可能不一样。 作死等级: 四颗星 脑残等级: 三颗星

小姐姐味道解决方式:把锁对象声明为final类型。

代码语言:javascript
复制
List listeners = new ArrayList();

void add(Listener listener, boolean upsert){
    synchronized(listeners){
        List results = new ArrayList();
        for(Listener ler:listeners){
        ...
        }
        listeners = results;
    }
}
六、线程循环未捕获异常

现象: 线程作业无法继续运行,不明终止。 原因: 未捕获循环中的异常,造成线程退出。 作死等级: 三颗星 脑残等级: 三颗星

小姐姐味道解决方式:习惯性捕获所有异常。

代码语言:javascript
复制
volatile boolean run = true;
void loop(){
    while(run){
        //do . sth
        int a = 1/0;
    }
}
七、volatile误作计数器

现象: 多线程计数结果有误。 原因: volatile保证可见性,不保证原子性,多线程操作并不能保证其正确性。 作死等级: 三颗星 脑残等级: 两颗星

小姐姐味道解决方式:直接使用Atomic类。

代码语言:javascript
复制
volatile count = 0;
void add(){
    ++count;
}
八、错误保护范围

现象: 虽然使用了线程安全的集合,但达不到同步效果。 原因: 操作要修改多个线程安全的集合,但操作本身不是原子的。 作死等级: 三颗星 脑残等级: 四颗星

小姐姐味道解决方式:弄明白要保护的代码逻辑域。

代码语言:javascript
复制
private final ConcurrentHashMap<String,Integer> nameToNumber;
private final ConcurrentHashMap<Integer,Salary> numberToSalary;
public int geBonusFor(String name) {
    Integer serialNum = nameToNumber.get(name);
    Salary salary = numberToSalary.get(serialNum);
    return salary.getBonus();
}

再比如下面的错误代码。

代码语言:javascript
复制
Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());

if(!map.containsKey("foo"))
    map.put("foo", "bar");
九、一些老的日期处理类

现象: 使用全局的Calendar, SimpleDateFormat等进行日期处理,发生异常或者数据不准确。 原因: 这俩东西不是线程安全的,并发调用会有问题。 作死等级: 三颗星 脑残等级: 三颗星

小姐姐味道解决方式:放在ThreadLocal中,建议使用线程安全的DateTimeFormatter。

代码语言:javascript
复制
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

Date dododo(String str){
    return format(str);
}
十、代码死锁

现象: 代码产生死锁和相互等待。 原因: 代码满足了下面四个条件:互斥;不可剥夺;请求和保持;循环等待。 作死等级: 两颗星 脑残等级: 一颗星

小姐姐味道解决方式:破坏这四个条件。或者少用同步。

下面是一段简单的死锁代码。

代码语言:javascript
复制
final Object lock1 = new Object();
final Object lock2 = new Object();
new Thread(new Runnable() {
    @Override
    public void run() {
        sleep(1000);
        synchronized (lock1) {
            synchronized (lock2) {
            }
        }
    }
}).start();
new Thread(new Runnable() {
    @Override
    public void run() {
        synchronized (lock2) {
            sleep(1000);
            synchronized (lock1) {
            }
        }
    }
}).start();
十一、long变量读取无效值

现象: 会读取到非设置的值。 原因: long变量读写不是原子的,可能会读到1个变量的高32位和另一个变量的低32位字节。 作死等级: 一颗星 脑残等级: 没有星

小姐姐味道解决方式:确保long和double变量的数据正确,可以加上volatile关键字。 扩展阅读(jdk10): https://docs.oracle.com/javase/specs/jls/se10/html/jls-17.html#jls-17.7 咦?怎么有11个?一定是多线程计算错误。

End

多线程的使用是及其复杂的,使用低级api出错的概率会成倍增加,对技能要求也较高。所幸,concurrent包使得这个过程方便了很多,但依然存在资源规划和同步失效的问题。小姐姐味道这里一个比较浅显但全面的总结:JAVA多线程使用场景和注意事项简版,但健壮的代码还要靠你自己去实践呀。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-06-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小姐姐味道 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • End
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档