线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。java线程安全通过synchronized同步锁实现。
以ArrayList和Vector模拟非线程安全的现象。
package com.gfzs.Thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class ThreadSafe {
public static void test() {
// 用来测试的List
List<Object> list = new ArrayList<Object>();
// 线程数量(1000)
int threadCount = 1000;
// 用来让主线程等待threadCount个子线程执行完毕
CountDownLatch countDownLatch = new CountDownLatch(threadCount);
// 启动threadCount个子线程
for (int i = 0; i < threadCount; i++) {
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());
}
public static void main(String[] args) {
// 进行10次测试
for(int i = 0; i < 10; i++)
{
test();
}
}
private static class MyThread implements Runnable {
private List<Object> list;
private CountDownLatch countDownLatch;
public MyThread(List<Object> list, CountDownLatch countDownLatch) {
this.list = list;
this.countDownLatch = countDownLatch;
}
public void run() {
// 每个线程向List中添加100个元素
for (int i = 0; i < 100; i++) {
list.add(new Object());
}
// 完成一个子线程
countDownLatch.countDown();
}
}
}
输出
99515
99600
99773
99795
99208
99791
99809
Exception in thread "Thread-7000" java.lang.ArrayIndexOutOfBoundsException: 163
at java.util.ArrayList.add(Unknown Source)
at com.gfzs.Thread.ThreadSafe$MyThread.run(ThreadSafe.java:54)
at java.lang.Thread.run(Unknown Source)
由于多线程访问非线程安全对象,所以每次执行的结果都不同,并且可能会抛出异常ArrayIndexOutOfBoundsException。
再用线程安全的Vector来进行测试,上面代码改变一处,test()方法中
List<Object> list = new ArrayList<Object>();
改为
List<Object> list = new Vector<Object>();
运行没有问题。