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

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

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

package Thread;

import java.util.List;
import java.util.concurrent.CountDownLatch; public class MyThread implements Runnable{
private List<Object> list;
private CountDownLatch countDownLatch;
public MyThread(){}
public MyThread(List<Object> list,CountDownLatch countDownLatch){
this.list=list;
this.countDownLatch=countDownLatch;
}
@Override
public void run() {
//给每个线程添加10个元素
for(int i=0;i<10;i++){
list.add(new Object());
}
//完成一个子线程
countDownLatch.countDown();
}
}

  

package Thread;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch; public class ThreadTest {
/**
* 这里要比较的是arraylist 和Vector来测试
* arraylist 是线程不安全的
* Vector 线程安全的
*
*/
public static void test(){
//用来测试的list集合
List<Object> list= new ArrayList<Object>();
//List<Object> list = new Vector<Object>();
//线程数
int threadCount =10000;
//用来让主线等待thread 个执行完毕
CountDownLatch count=new CountDownLatch(threadCount);
for(int i=0;i<threadCount;i++){
Thread thread=new Thread(new MyThread(list, count));
thread.start();
}
try {
//主线程所有都执行完成后,再向下执行
count.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(list.size());
}
public static void main(String[] args) {
for(int i=0;i<10;i++){
test();
}
}
}

 运行结构:

99995
99998
99989
99973
99894
99970
99974
99977
99990
99989

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

package Thread;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch; public class ThreadTest {
/**
* 这里要比较的是arraylist 和Vector来测试
* arraylist 是线程不安全的
* Vector 线程安全的
*
*/
public static void test(){
//用来测试的list集合
//List<Object> list= new ArrayList<Object>();
List<Object> list = new Vector<Object>();
//线程数
int threadCount =10000;
//用来让主线等待thread 个执行完毕
CountDownLatch count=new CountDownLatch(threadCount);
for(int i=0;i<threadCount;i++){
Thread thread=new Thread(new MyThread(list, count));
thread.start();
}
try {
//主线程所有都执行完成后,再向下执行
count.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(list.size());
}
public static void main(String[] args) {
for(int i=0;i<10;i++){
test();
}
}
}

  这样运行的结果:

100000
100000
100000
100000
100000
100000
100000
100000
100000
100000

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

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

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

下面举个synchronized同步的例子:

package Thread1;

public class Bank {
private int sum = 0; public void add(int n) {
sum = sum + n;
System.out.println("sum= " + sum);
}
} package Thread1;
public class Cus implements Runnable {
Bank b = new Bank();
@Override
public void run() {
for (int i = 0; i < 3; i++) {
b.add(100);
} }
} package Thread1; public class Test {
public static void main(String[] args) {
Cus c = new Cus();
for (int i = 0; i < 3; i++) {
new Thread(c).start();
}
}
}

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

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

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

package Thread1;

public class Bank {
private int sum = 0; public void add(int n) {
sum = sum + n;
System.out.println("sum= " + sum);
}
} package Thread1;
public class Cus implements Runnable {
Bank b = new Bank();
@Override public void run() {
synchronized(this){
for (int i = 0; i < 3; i++) {
b.add(100);
}
}
}
} package Thread1; public class Test {
public static void main (String [] args) {
Cus c = new Cus();
for(int i=0;i<3;i++){
new Thread(c).start();
}
}
}

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

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. $.grep(array, callback, [invert])过滤,常用

    $.grep(array, callback, [invert])过滤,常用 解释: 使用过滤函数过滤数组元素.此函数至少传递两个参数(第三个参数为true或false,对过滤函数返回值取反,个人觉得 ...

  2. ZooKeeper设置ACL权限控制

    ZK的节点有5种操作权限:CREATE.READ.WRITE.DELETE.ADMIN 也就是 增.删.改.查.管理权限,这5种权限简写为crwda(即:每个单词的首字符缩写)注:这5种权限中,del ...

  3. crontab 系列

    crontab是一个很方便的在unix/linux系统上定时(循环)执行某个任务的程序使用cron服务,用 service crond status 查看 cron服务状态,如果没有启动则 servi ...

  4. [转]hp电脑重装win7 64位 后 所有软件都装不上问题

    hp 电脑重装后 所有软件都装不上问题 装了近100来次机,第一次遇到这样的. bug描述: 新笔记本刚装了纯净版的64位旗舰版win7,想装软件,就弹出已停止工作.比如装火狐浏览器,弹出火狐浏览器网 ...

  5. python第二十天-----Django补充

    学习python已经20天了啊,从一个不萌萌哒的战5渣升级到了一个萌萌哒的战5渣 1.分页(这是一个很通用的模块,不论在任何框架里都可以使用哦) class Page(object): def __i ...

  6. oracle 表被锁定 杀死进程

    /*查出被锁biao*/ select b.owner,b.object_name,a.session_id,a.locked_mode from v$locked_object a,dba_obje ...

  7. hdu 1849(Rabbit and Grass) 尼姆博弈

    Rabbit and Grass Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  8. C++ Primer Plus 笔记记录

    (一) /a 这个转移字符竟然能调用计算机的硬件 喇叭~~ 对于float c++只能保证6位有效数字 似乎 double是13位 cout.setf(ios_base::fixed, ios_bas ...

  9. 【转】+【举例】ArcGIS中的坐标系统定义与投影转换

    背景知识: UTM (Universal Transverse Mercator)坐标系是由美国军方在1947提出的.虽然我们仍然将其看作与"高斯-克吕格"相似的坐标系统,但实际上 ...

  10. Spark RDD aggregateByKey

    aggregateByKey 这个RDD有点繁琐,整理一下使用示例,供参考 直接上代码 import org.apache.spark.rdd.RDD import org.apache.spark. ...