多线程-- 五.线程问题常见的类 和其对应的同步、并发容器

 

线程不安全类

 

什么是线程不安全的类?

    简单来说,如果一个类对象同时可以被多个线程访问,如果不做处理,容易表现出线程不安全现象。

 

1.StringBuilder和StringBuffer

    StringBuilder是线程不安全的

    StringBuffer是线程安全的

    因为StringBuffer的源码中,基本所有的方法上都加了synchronized关键字;而StringBuilder并不是。

    但是正因为StringBuffer用了synchronized,所以同一时间只能有一条线程访问,造成效率低,性能上有损耗。

    所以如果不考虑多线程访问情况下,大多用StringBuilder来实现。因为在局部变量使用中,线程封闭,不涉及线程问题。

    这就是JAVA为什么提供了两个字符串拼接类的原因。

 

2.SimpleDateFormat和JodaTime包

    SimpleDateFormat是日期转换的类,是线程不安全的。因为在多线程情况下运行,直接抛异常。

    如果想使用这个类的话,要注意,不要声明在全局变量中,可以声明在方法中,局部变量,不涉及线程问题就可以。

    JodaTime包本质上不是Java提供的,是一个单独的包。也是一个日期转换的,这个包里面的类是线程安全的。

    包的依赖如下:

    

   

3.ArrayList,HashSet,Hashmap等Collections

    ArrayList,HashSet,Hashmap都是线程不安全的。

如何处理能将上面的几个类转换为线程安全的呢?

1.使用同步容器也不是线程完全安全的,完全安全的话需要使用并发容器,所以基本没人使用这个了

    ①.直接用对应的线程安全类

        ArrayList --> Vector,Stack

        Hashmap --> HashTable

    ②.用Collections.synchronizedXXX方法实现转换 (List,Set,Map)

 

    Vector类实现了List接口,它的方法都使用了synchronized关键字来修饰

    Stack类继承了Vector类,就是咱们数据结构中的栈。它的方法都使用了synchronized来修饰

    HashTable的方法都使用了synchronized关键字来修饰,但是它的key,value不能为NULL,需注意。

 

    Vector类,迭代器遍历的时候,如果对其进行了增删操作,会出现并发修改异常。普通for循环不会。

    举例:

    public static Object getLast(Vector list) {

            int lastIndex = list.size() - 1;

            return list.get(lastIndex);

    }

    public static void deleteLast(Vector list) {

            int lastIndex = list.size() - 1;

            list.remove(lastIndex);

    }

 

    虽然上面的方法看起来没有问题,Vector自身的方法也是同步的,但是在多线程环境中还是隐藏着问题。如果有两个线程A,B同时调用上面的两个方法,假设list的大小为10,这里计算得到的lastIndex为9,线程B首先执行了删除操作(多线程之间操作执行的不确定性导致),而后线程A调用了list.get方法,这时就会发生数组越界异常。导致问题的原因就是上面的复合操作不是原子操作,这里可以通过在方法内部使用list对象锁来实现原子操作。

 

2.使用并发容器

    (单独一个笔记写 :线程安全-并发容器)

 

 

线程不安全的写法

    

1.先检查后执行的写法

    if ( ) { }

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值