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

线程安全不安全,主要是在多线程执行的情况下,如果由于线程之间抢占资源而造成程序的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

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