经常看到一些类,有的说线程安全,有的说线程不安全,顿时懵逼。
线程安全不安全,主要是在多线程执行的情况下,如果由于线程之间抢占资源而造成程序的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
每天进步一点点,坚持下去