经常看到一些类,有的说线程安全,有的说线程不安全,顿时懵逼。

线程安全不安全,主要是在多线程执行的情况下,如果由于线程之间抢占资源而造成程序的bug即为线程不安全,下面就拿arraylist 和Vector来举个例子:

这里的arraylist 是线程不安全的,Vector是线程安全的

  1. package Thread;
  2.  
  3. import java.util.List;
  4. import java.util.concurrent.CountDownLatch;
  5.  
  6. public class MyThread implements Runnable{
  7. private List<Object> list;
  8. private CountDownLatch countDownLatch;
  9. public MyThread(){}
  10. public MyThread(List<Object> list,CountDownLatch countDownLatch){
  11. this.list=list;
  12. this.countDownLatch=countDownLatch;
  13. }
  14. @Override
  15. public void run() {
  16. //给每个线程添加10个元素
  17. for(int i=0;i<10;i++){
  18. list.add(new Object());
  19. }
  20. //完成一个子线程
  21. countDownLatch.countDown();
  22. }
  23. }

  

  1. package Thread;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import java.util.Vector;
  6. import java.util.concurrent.CountDownLatch;
  7.  
  8. public class ThreadTest {
  9. /**
  10. * 这里要比较的是arraylist 和Vector来测试
  11. * arraylist 是线程不安全的
  12. * Vector 线程安全的
  13. *
  14. */
  15. public static void test(){
  16. //用来测试的list集合
  17. List<Object> list= new ArrayList<Object>();
  18. //List<Object> list = new Vector<Object>();
  19. //线程数
  20. int threadCount =10000;
  21. //用来让主线等待thread 个执行完毕
  22. CountDownLatch count=new CountDownLatch(threadCount);
  23. for(int i=0;i<threadCount;i++){
  24. Thread thread=new Thread(new MyThread(list, count));
  25. thread.start();
  26. }
  27. try {
  28. //主线程所有都执行完成后,再向下执行
  29. count.await();
  30. } catch (InterruptedException e) {
  31. // TODO Auto-generated catch block
  32. e.printStackTrace();
  33. }
  34. System.out.println(list.size());
  35. }
  36. public static void main(String[] args) {
  37. for(int i=0;i<10;i++){
  38. test();
  39. }
  40. }
  41. }

 运行结构:

99995
99998
99989
99973
99894
99970
99974
99977
99990
99989

当使用Vector时,即把测试的集合换一下

  1. package Thread;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import java.util.Vector;
  6. import java.util.concurrent.CountDownLatch;
  7.  
  8. public class ThreadTest {
  9. /**
  10. * 这里要比较的是arraylist 和Vector来测试
  11. * arraylist 是线程不安全的
  12. * Vector 线程安全的
  13. *
  14. */
  15. public static void test(){
  16. //用来测试的list集合
  17. //List<Object> list= new ArrayList<Object>();
  18. List<Object> list = new Vector<Object>();
  19. //线程数
  20. int threadCount =10000;
  21. //用来让主线等待thread 个执行完毕
  22. CountDownLatch count=new CountDownLatch(threadCount);
  23. for(int i=0;i<threadCount;i++){
  24. Thread thread=new Thread(new MyThread(list, count));
  25. thread.start();
  26. }
  27. try {
  28. //主线程所有都执行完成后,再向下执行
  29. count.await();
  30. } catch (InterruptedException e) {
  31. // TODO Auto-generated catch block
  32. e.printStackTrace();
  33. }
  34. System.out.println(list.size());
  35. }
  36. public static void main(String[] args) {
  37. for(int i=0;i<10;i++){
  38. test();
  39. }
  40. }
  41. }

  这样运行的结果:

100000
100000
100000
100000
100000
100000
100000
100000
100000
100000

很明显,使用Vector 这个类运行正确,这就是所谓的线程安全

当然,这只是代码层面上的,其实多线程不安全,主要因为cpu分配机制,谁获得了cpu谁就能执行,因此造成了线程的不安全.

我们可以使用synchronized  关键字来同步代码块,达到线程安全:

下面举个synchronized同步的例子:

  1. package Thread1;
  2.  
  3. public class Bank {
  4. private int sum = 0;
  5.  
  6. public void add(int n) {
  7. sum = sum + n;
  8. System.out.println("sum= " + sum);
  9. }
  10. }
  11.  
  12. package Thread1;
  13. public class Cus implements Runnable {
  14. Bank b = new Bank();
  15. @Override
  16. public void run() {
  17. for (int i = 0; i < 3; i++) {
  18. b.add(100);
  19. }
  20.  
  21. }
  22. }
  23.  
  24. package Thread1;
  25.  
  26. public class Test {
  27. public static void main(String[] args) {
  28. Cus c = new Cus();
  29. for (int i = 0; i < 3; i++) {
  30. new Thread(c).start();
  31. }
  32. }
  33. }

  没有使用synchronized修饰的时候,运行结构是:

sum= 100
sum= 400
sum= 500
sum= 300
sum= 200
sum= 600
sum= 800
sum= 700
sum= 900

当然synchronized 必须要在线程运行的代码块中修饰:

  1. package Thread1;
  2.  
  3. public class Bank {
  4. private int sum = 0;
  5.  
  6. public void add(int n) {
  7. sum = sum + n;
  8. System.out.println("sum= " + sum);
  9. }
  10. }
  11.  
  12. package Thread1;
  13. public class Cus implements Runnable {
  14. Bank b = new Bank();
  15. @Override
  16.  
  17. public void run() {
  18. synchronized(this){
  19. for (int i = 0; i < 3; i++) {
  20. b.add(100);
  21. }
  22. }
  23. }
  24. }
  25.  
  26. package Thread1;
  27.  
  28. public class Test {
  29. public static void main (String [] args) {
  30. Cus c = new Cus();
  31. for(int i=0;i<3;i++){
  32. new Thread(c).start();
  33. }
  34. }
  35. }

  这样保证,每次只有一个线程在运行,结果为:

sum= 100
sum= 200
sum= 300
sum= 400
sum= 500
sum= 600
sum= 700
sum= 800
sum= 900

OK,OVER

每天进步一点点,坚持下去

java 线程安全不线程不安全的更多相关文章

  1. 关于Java中进程和线程的详解

    一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而 ...

  2. 0041 Java学习笔记-多线程-线程池、ForkJoinPool、ThreadLocal

    什么是线程池 创建线程,因为涉及到跟操作系统交互,比较耗费资源.如果要创建大量的线程,而每个线程的生存期又很短,这时候就应该使用线程池了,就像数据库的连接池一样,预先开启一定数量的线程,有任务了就将任 ...

  3. 0040 Java学习笔记-多线程-线程run()方法中的异常

    run()与异常 不管是Threade还是Runnable的run()方法都没有定义抛出异常,也就是说一条线程内部发生的checked异常,必须也只能在内部用try-catch处理掉,不能往外抛,因为 ...

  4. 0039 Java学习笔记-多线程-线程控制、线程组

    join线程 假如A线程要B线程去完成一项任务,在B线程完成返回之前,不进行下一步执行,那么就可以调用B线程的join()方法 join()方法的重载: join():等待不限时间 join(long ...

  5. java之并发编程线程池的学习

    如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. java.uitl.concurrent.Thre ...

  6. java线程 - 多线程 - 守护线程

    1.多线程执行者/处理类 都是Runnable的实现类(如自定义类实现Runnable 或 java原生的Thread.FutureTask),但最后都必须封装成Thread线程类由Thread.st ...

  7. Java并发编程:线程池的使用

    Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了, ...

  8. Java多线程系列--“JUC线程池”06之 Callable和Future

    概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...

  9. java: Thread 和 runnable线程类

    java: Thread 和 runnable线程类 Java有2种实现线程的方法:Thread类,Runnable接口.(其实Thread本身就是Runnable的子类) Thread类,默认有ru ...

  10. Java用户线程和守护线程

    今天看Java一个关于多线程返回值方式的示例,发现一个自己不太能理解的问题,就是在主线程中启动了几个工作线程,主线程中也没有join,工作线程居然也是正常输出了回调的结果.这个跟linux C++下的 ...

随机推荐

  1. spring整合freemarker

    一.配置maven <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www ...

  2. c++ 别名

    #include <iostream> int main() { ; // 别名 int &ref = i; std::cout << &i << ...

  3. Windows服务二:测试新建的服务、调试Windows服务

    一.测试Windows服务 为了使Windows服务程序能够正常运行,我们需要像创建一般应用程序那样为它创建一个程序的入口点.像其他应用程序一样,Windows服务也是在Program.cs的Main ...

  4. Windows服务一:新建Windows服务、安装、卸载服务

    Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序.这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面 ...

  5. MySql 数据库导入到 SQL Service

    1.下载安装ODBC驱动程序 地址:http://dev.mysql.com/downloads/connector/odbc/ 注意:系统的版本问题( 我的是64位的win7系统,但是SQL Ser ...

  6. C# delegate

    1. delegate example1 class Program { public delegate int MyDelegate(int i); int MyFunc(int i) { retu ...

  7. C++对象模型

    1.类布局 1.1简单类对象的内存布局 class A { public: void f(); private: int i; char c; static int s; }; 简单对象的内存布局:非 ...

  8. 说说JSON和JSONP,也许你会豁然开朗(转)

    前言 由于Sencha Touch 2这种开发模式的特性,基本决定了它原生的数据交互行为几乎只能通过AJAX来实现. 当然了,通过调用强大的PhoneGap插件然后打包,你可以实现100%的Socke ...

  9. 简单的html和css

    整体图太大了,看不太清楚,下面是分开的图 第一张: 第二张:

  10. EhCache RMI 分布式缓存/缓存集群

    EhCache 系统简介 EhCache 是一个纯 Java 的进程内缓存框架,具有快速.精干等特点. EhCache 的主要特性有: 快速.精干 简单: 多种缓存策略: 缓存数据有两级:内存和磁盘, ...