Java面试和笔试中常常会问到html
String线程安全StringBuffer线程安全StringBuilder非线程安全java
HashMap非线程安全的HashTable线程安全的vector线程安全的面试
可是接下来会问你,不安全为何还会用,由于HashMap效率更高,若是想让它变成安全的,加同步锁()安全
那什么叫线程安全什么叫非线程安全呢?学习
1、线程测试
什么叫作线程呢?ui
建议能够看一下阮一峰大神的博客:http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.htmlthis
讲的很是通俗易懂,留言中的内容也要看,由于是转载的,有不少地方值得商榷。spa
2、线程安全和非线程安全线程
当多个线程同时操做同一个对象,修改某一个属性的时候,不会发生问题就称之为“线程安全”
可能会出现问题,就是“非线程安全的”
好比说ArrayList和vector来讲
在主线程中,new了一个ArrayList线程,如今开100个线程,每一个线程向arraylist中存放100个元素,最后ArrayList中有多少个对象,10000?
先建立一个线程类(另一篇文章会总结学习一下线程的三种实现方式)
1 class MyThread implements Runnable 2 { 3 private List<Object> list; 4 5 private CountDownLatch countDownLatch; 6 7 public MyThread(List<Object> list, CountDownLatch countDownLatch) 8 { 9 this.list = list; 10 this.countDownLatch = countDownLatch; 11 } 12 13 public void run() 14 { 15 // 每一个线程向List中添加100个元素 16 for(int i = 0; i < 100; i++) 17 { 18 list.add(new Object()); 19 } 20 21 // 完成一个子线程 22 countDownLatch.countDown(); 23 } 24 }
1 package threadTest; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 import java.util.concurrent.CountDownLatch; 6 7 public class Test { 8 public static void test() 9 { 10 // 用来测试的List 11 List<Object> list = new ArrayList<Object>(); 12 13 // 线程数量(1000) 14 int threadCount = 1000; 15 16 // 用来让主线程等待threadCount个子线程执行完毕 17 CountDownLatch countDownLatch = new CountDownLatch(threadCount); 18 19 // 启动threadCount个子线程 20 for(int i = 0; i < threadCount; i++) 21 { 22 Thread thread = new Thread(new MyThread(list, countDownLatch)); 23 thread.start(); 24 } 25 26 try 27 { 28 // 主线程等待全部子线程执行完成,再向下执行 29 countDownLatch.await(); 30 } 31 catch (InterruptedException e) 32 { 33 e.printStackTrace(); 34 } 35 36 // List的size 37 System.out.println(list.size()); 38 } 39 public static void main(String[] args) 40 { 41 // 进行10次测试 42 for(int i = 0; i < 10; i++) 43 { 44 test(); 45 } 46 } 47 48 }
最后结果:
99799
99814
99765
100000
99868
99830
100000
99915
99858
99830
可是有时候会产生异常
这就是所谓的非线程安全
接下来换成线程安全的vector
将test里边的ArrayList换成vector
List<Object> list = new ArrayList<Object>();
List<Object> list = new Vector<Object>();
100000
100000
100000
100000
100000
100000
100000
100000
100000
100000
输出结果
在多试几回,仍是同样的结果,由于vector是线程安全的,换成LinkedList结果和ArrayList相似,由于LinkedList也是非线程安全的
3、如何取舍
当存在多个线程操做同一对象的时候,就采用vector等线程安全的,若是不涉及,就采用ArrayList等,由于效率高
若是想要用ArrayList也能够,线程安全必需要使用不少synchronized关键字来同步控制,加同步锁
List<Object> list = Collections.synchronizedList(new ArrayList<Object>());
synchronized关键字同步,可是这样会下降效率
另一种,实在方法前边用synchronized修饰方法
一个计数器类
class Counter { private int count = 0; public int getCount() { return count; } public void addCount() { count++; } }
建立线程类
1 class MyThread implements Runnable 2 { 3 private Counter counter; 4 5 private CountDownLatch countDownLatch; 6 7 public MyThread(Counter counter, CountDownLatch countDownLatch) 8 { 9 this.counter = counter; 10 this.countDownLatch = countDownLatch; 11 } 12 13 public void run() 14 { 15 // 每一个线程向Counter中进行10000次累加 16 for(int i = 0; i < 10000; i++) 17 { 18 counter.addCount(); 19 } 20 21 // 完成一个子线程 22 countDownLatch.countDown(); 23 } 24 }
主线程
1 public class Main 2 { 3 public static void main(String[] args) 4 { 5 // 进行10次测试 6 for(int i = 0; i < 10; i++) 7 { 8 test(); 9 } 10 } 11 12 public static void test() 13 { 14 // 计数器 15 Counter counter = new Counter(); 16 17 // 线程数量(1000) 18 int threadCount = 1000; 19 20 // 用来让主线程等待threadCount个子线程执行完毕 21 CountDownLatch countDownLatch = new CountDownLatch(threadCount); 22 23 // 启动threadCount个子线程 24 for(int i = 0; i < threadCount; i++) 25 { 26 Thread thread = new Thread(new MyThread(counter, countDownLatch)); 27 thread.start(); 28 } 29 30 try 31 { 32 // 主线程等待全部子线程执行完成,再向下执行 33 countDownLatch.await(); 34 } 35 catch (InterruptedException e) 36 { 37 e.printStackTrace(); 38 } 39 40 // 计数器的值 41 System.out.println(counter.getCount()); 42 } 43 }
9760282
9999073
9999969
9990000
9998743
9965715
9990000
9994370
9990945
9993745
建立一个线程安全的计数器
class Counter { private int count = 0; public int getCount() { return count; } public synchronized void addCount() { count++; } }
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
10000000
输出结果