ArrayList和Vector有什么区别?HashMap和HashTable有什么区别?StringBuilder和StringBuffer有什么区别?这些都是Java面试中常见的基础问题 面对这样的问题 回答是 ArrayList是非线程安全的 Vector是线程安全的 HashMap是非线程安全的 HashTable是线程安全的 StringBuilder是非线程安全的 StringBuffer是线程安全的 因为这是昨晚刚背的《Java面试题大全》上面写的 此时如果继续问 什么是线程安全?线程安全和非线程安全有什么区别?分别在什么情况下使用?这样一连串的问题 一口老血就喷出来了…
非线程安全的现象模拟
这里就使用ArrayList和Vector二者来说明
下面的代码 在主线程中new了一个非线程安全的ArrayList 然后开 个线程分别向这个ArrayList里面添加元素 每个线程添加 个元素 等所有线程执行完成后 这个ArrayList的size应该是多少?应该是 个?
[java]
public class Main
{
public static void main(String[] args)
{
// 进行 次测试
for(int i = i <i++)
{
test()
}
}
public static void test()
{
// 用来测试的List
List<Object>list = new ArrayList<Object>()
// 线程数量( )
int threadCount =
// 用来让主线程等待threadCount个子线程执行完毕
CountDownLatch countDownLatch = new CountDownLatch(threadCount)
// 启动threadCount个子线程
for(int i = i <threadCounti++)
{
Thread thread = new Thread(new MyThread(list countDownLatch))
thread start()
}
try
{
// 主线程等待所有子线程执行完成 再向下执行
countDownLatch await()
}
catch (InterruptedException e)
{
e printStackTrace()
}
// List的size
System out println(list size())
}
}
class MyThread implements Runnable
{
private List<Object>list
private CountDownLatch countDownLatch
public MyThread(List<Object>list CountDownLatch countDownLatch)
{
this list = list
untDownLatch = countDownLatch
}
public void run()
{
// 每个线程向List中添加 个元素
for(int i = i <i++)
{
list add(new Object())
}
// 完成一个子线程
untDown()
}
}
public class Main
{
public static void main(String[] args)
{
// 进行 次测试
for(int i = i <i++)
{
test()
}
}
public static void test()
{
// 用来测试的List
List<Object>list = new ArrayList<Object>()
// 线程数量( )
int threadCount =
// 用来让主线程等待threadCount个子线程执行完毕
CountDownLatch countDownLatch = new CountDownLatch(threadCount)
// 启动threadCount个子线程
for(int i = i <threadCounti++)
{
Thread thread = new Thread(new MyThread(list countDownLatch))
thread start()
}
try
{
// 主线程等待所有子线程执行完成 再向下执行
countDownLatch await()
}
catch (InterruptedException e)
{
e printStackTrace()
}
// List的size
System out println(list size())
}
}
class MyThread implements Runnable
{
private List<Object>list
private CountDownLatch countDownLatch
public MyThread(List<Object>list CountDownLatch countDownLatch)
{
this list = list
untDownLatch = countDownLatch
}
public void run()
{
// 每个线程向List中添加 个元素
for(int i = i <i++)
{
list add(new Object())
}
// 完成一个子线程
untDown()
}
}
上面进行了 次测试(为什么要测试 次?因为非线程安全并不是每次都会导致问题)
输出结果
上面的输出结果发现 并不是每次测试结果都是 有好几次测试最后ArrayList的size小于 甚至时不时会抛出个IndexOutOfBoundsException异常 (如果没有这个现象可以多试几次)
这就是非线程安全带来的问题了 上面的代码如果用于生产环境 就会有隐患就会有BUG了
再用线程安全的Vector来进行测试 上面代码改变一处 test()方法中
[java]
List<Object>list = new ArrayList<Object>()
List<Object>list = new ArrayList<Object>()改成
[java]
List<Object>list = new Vector<Object>()
List<Object>list = new Vector<Object>()
再运行程序
输出结果
再多跑几次 发现都是 没有任何问题 因为Vector是线程安全的 在多线程操作同一个Vector对象时 不会有任何问题
再换成LinkedList试试 同样还会出现ArrayList类似的问题 因为LinkedList也是非线程安全的
二者如何取舍
非线程安全是指多线程操作同一个对象可能会出现问题 而线程安全则是多线程操作同一个对象不会有问题
线程安全必须要使用很多synchronized关键字来同步控制 所以必然会导致性能的降低
所以在使用的时候 如果是多个线程操作同一个对象 那么使用线程安全的Vector 否则 就使用效率更高的ArrayList
非线程安全!=不安全
有人在使用过程中有一个不正确的观点 我的程序是多线程的 不能使用ArrayList要使用Vector 这样才安全
非线程安全并不是多线程环境下就不能使用 注意我上面有说到 多线程操作同一个对象 注意是同一个对象 比如最上面那个模拟 就是在主线程中new的一个ArrayList然后多个线程操作同一个ArrayList对象
如果是每个线程中new一个ArrayList 而这个ArrayList只在这一个线程中使用 那么肯定是没问题的
线程安全的实现
线程安全是通过线程同步控制来实现的 也就是synchronized关键字
在这里 我用代码分别实现了一个非线程安全的计数器和线程安全的计数器Counter 并对他们分别进行了多线程测试
非线程安全的计数器
[java]
public class Main
{
public static void main(String[] args)
{
// 进行 次测试
for(int i = i <i++)
{
test()
}
}
public static void test()
{
// 计数器
Counter counter = new Counter()
// 线程数量( )
int threadCount =
// 用来让主线程等待threadCount个子线程执行完毕
CountDownLatch countDownLatch = new CountDownLatch(threadCount)
// 启动threadCount个子线程
for(int i = i <threadCounti++)
{
Thread thread = new Thread(new MyThread(counter countDownLatch))
thread start()
}
try
{
// 主线程等待所有子线程执行完成 再向下执行
countDownLatch await()
}
catch (InterruptedException e)
{
e printStackTrace()
}
// 计数器的值
System out println(counter getCount())
}
}
class MyThread implements Runnable
{
private Counter counter
private CountDownLatch countDownLatch
public MyThread(Counter counter CountDownLatch countDownLatch)
{
unter = counter
untDownLatch = countDownLatch
}
public void run()
{
// 每个线程向Counter中进行 次累加
for(int i = i <i++)
{
counter addCount()
}
// 完成一个子线程
untDown()
}
}
class Counter
{
private int count =
public int getCount()
{
return count
}
public void addCount()
{
count++
}
}
public class Main
{
public static void main(String[] args)
{
// 进行 次测试
for(int i = i <i++)
{
test()
}
}
public static void test()
{
// 计数器
Counter counter = new Counter()
// 线程数量( )
int threadCount =
// 用来让主线程等待threadCount个子线程执行完毕
CountDownLatch countDownLatch = new CountDownLatch(threadCount)
// 启动threadCount个子线程
for(int i = i <threadCounti++)
{
Thread thread = new Thread(new MyThread(counter countDownLatch))
thread start()
}
try
{
// 主线程等待所有子线程执行完成 再向下执行
countDownLatch await()
}
catch (InterruptedException e)
{
e printStackTrace()
}
// 计数器的值
System out println(counter getCount())
}
}
class MyThread implements Runnable
{
private Counter counter
private CountDownLatch countDownLatch
public MyThread(Counter counter CountDownLatch countDownLatch)
{
unter = counter
untDownLatch = countDownLatch
}
public void run()
{
// 每个线程向Counter中进行 次累加
for(int i = i <i++)
{
counter addCount()
}
// 完成一个子线程
untDown()
}
}
class Counter
{
private int count =
public int getCount()
{
return count
}
public void addCount()
{
count++
}
}
上面的测试代码中 开启 个线程 每个线程对计数器进行 次累加 最终输出结果应该是
但是上面代码中的Counter未进行同步控制 所以非线程安全
输出结果
稍加修改 把Counter改成线程安全的计数器
[java]
class Counter
{
private int count =
public int getCount()
{
return count
}
public synchronized void addCount()
{
count++
}
}
class Counter
{
private int count =
public int getCount()
{
return count
}
public synchronized void addCount()
{
count++
}
}
上面只是在addCount()方法中加上了synchronized同步控制 就成为一个线程安全的计数器了 再执行程序
输出结果
lishixinzhi/Article/program/Java/gj/201311/27519
String是不可变类,所以是线程安全的。
1、所有不可变类都是线程安全的,线程安全的类不一定是不可变类,如StringBuffer是可变类,靠锁实现线程安全。
2、StringBuffer方法上都加了synchronized,StringBuilder没有,StringBuilder在多线程情况下是会出现问题,但是线程安全线程非安全指的是你业务环境需要线程安全考虑不考虑。多并发网络编程这块会考虑这些。
在Java语言中,线程是一种特殊的对象,它必须由Thread类或其子(孙)类来创建。
通常有两种方法来创建线程:
其一,使用型构为Thread(Runnable)的构造子将一个实现了Runnable接口的对象包装成一个线程。
其二,从Thread类派生出子类并重写run方法,使用该子类创建的对象即为线程。
值得注意的是Thread类已经实现了Runnable接口,因此,任何一个线程均有它的run方法,而run方法中包含了线程所要运行的代码。线程的活动由一组方法来控制。Java语言支持多个线程的同时执行,并提供多线程之间的同步机制(关键字为synchronized)。
线程安全主要在体现在这三个方面:1.原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);
2.可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);
3.有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。
所以想保证线性安全的话只要从这三个方面入手就可以了。