Java线程安全和非线程安全
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 list = new ArrayList(); // 线程数量( ) int threadCount = ; // 用来让主线程等待threadCount个子线程执行完毕 CountDownLatch countDownLatch = new CountDownLatch(threadCount); // 启动threadCount个子线程 for(int i = ; 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()); } } class MyThread implements Runnable { private List list; private CountDownLatch countDownLatch; public MyThread(List 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 list = new ArrayList(); // 线程数量( ) int threadCount = ; // 用来让主线程等待threadCount个子线程执行完毕 CountDownLatch countDownLatch = new CountDownLatch(threadCount); // 启动threadCount个子线程 for(int i = ; 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()); } } class MyThread implements Runnable { private List list; private CountDownLatch countDownLatch; public MyThread(List 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 list = new ArrayList(); List list = new ArrayList();改成 [java] List list = new Vector(); List list = new Vector(); 再运行程序 输出结果 再多跑几次 发现都是 没有任何问题 因为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 < threadCount; i++) { 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 < threadCount; i++) { 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
如何实现线程安全?
1: 加锁 利用Synchronized或者ReenTrantLock来对不安全对象进行加锁,来实现线程执行的串行化,从而保证多线程同时操作对象的安全性,一个是语法层面的互斥锁,一个是API层面的互斥锁.
2: 非阻塞同步来实现线程安全。原理就是:通俗点讲,就是先进性操作,如果没有其他线程争用共享数据,那操作就成功了;如果共享数据有争用,产生冲突,那就再采取其他措施(最常见的措施就是不断地重试,直到成功为止)。这种方法需要硬件的支持,因为我们需要操作和冲突检测这两个步骤具备原子性。通常这种指令包括CAS SC,FAI TAS等。
3:线程本地化,一种无同步的方案,就是利用Threadlocal来为每一个线程创造一个共享变量的副本来(副本之间是无关的)避免几个线程同时操作一个对象时发生线程安全问题
什么是线程安全?
线程安全
计算机程序代码中的概念
线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。
基本信息
中文名
线程安全
外文名
thread
类别
线程
目录
概述
多个线程访问同一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他操作,调用这个对象的行为都可以获得正确的结果,那么这个对象就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
线程安全问题大多是由全局变量及静态变量引起的,局部变量逃逸也可能导致线程安全问题。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
什么是线程安全?
线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。当对一个复杂对象进行某种操作时,从操作开始到操作结束,被操作的对象往往会经历若干非法的中间状态。调用一个函数(假设该函数是正确的)操作某对象常常会使该对象暂时陷入不可用的状态(通常称为不稳定状态),等到操作完全结束,该对象才会重新回到完全可用的状态。如果其他线程企图访问一个处于不可用状态的对象,该对象将不能正确响应从而产生无法预料的结果,如何避免这种情况发生是线程安全性的核心问题。扩展资料:简单类比线程安全性问题跟外科医生做手术有点象,尽管手术的目的是改善患者的健康,但医生把手术过程分成了几个步骤,每个步骤如果不是完全结束的话,都会严重损害患者的健康。想想看,如果一个医生切开患者的胸腔后要休三周假会怎么样?然而单线程的程序中是不存在这种问题的,因为在一个线程更新某对象的时候不会有其他线程也去操作同一个对象。(除非其中有异常,异常是可能导致上述问题的。当一个正在更新某对象的线程因异常而中断更新过程后,再去访问没有完全更新的对象,会出现同样的问题)