Java线程学习笔记之线程安全与不安全

2/22/2017来源:ASP.NET技巧人气:2072

在JDK API,有很多类上面都写着是线程安全或者线程不安全,比如StringBuilder就是线程不安全的类,在多线程的情况下,如果需要同步,则建议使用StringBuffer。 存在成员变量的类用于多线程时是不安全的,不安全体现在这个成员变量可能发生非原子性的操作,而变量定义在方法内也就是局部变量是线程安全的。在日常开发中,通常需要考虑成员变量或者说全局变量在多线程环境下,是否会引发一些问题。以下是示例: 创建一个线程不安全的类:

public class Count { PRivate int num;//成员变量 public void count() { for(int i=1;i<=10;i++){ num+=i; } System.out.println("线程:"+Thread.currentThread().getName()+";数据:"+num); } }

创建多线程并执行

public class ThreadSecurityTest { public static void main(String[] args){ Runnable runnable = new Runnable() { Count count = new Count(); @Override public void run() { count.count(); } }; for(int i=0;i<10;i++){ new Thread(runnable).start(); } } }

这里,我们想要的结果是输出的值是一样的55 而实际上的输出结果是(会有不同的输出结果,反正不会是上面的):

线程:Thread-0;数据:55 线程:Thread-3;数据:165 线程:Thread-2;数据:275 线程:Thread-9;数据:495 线程:Thread-5;数据:550 线程:Thread-4;数据:220 线程:Thread-1;数据:165 线程:Thread-6;数据:330 线程:Thread-8;数据:440 线程:Thread-7;数据:385

完全乱掉,也就是说,所有的线程都在任意时刻读取和修改成员变量num的值,而且没有同步。也可以说这种错误是由于成员变量造成的 当我们把Count类的成员变量num变为方法变量的时候:

public class Count { //private int num; public synchronized void count() { int num = 0; for(int i=1;i<=10;i++){ num+=i; } System.out.println("线程:"+Thread.currentThread().getName()+";数据:"+num); } }

结果

线程:Thread-0;数据:55 线程:Thread-3;数据:55 线程:Thread-4;数据:55 线程:Thread-2;数据:55 线程:Thread-1;数据:55 线程:Thread-7;数据:55 线程:Thread-9;数据:55 线程:Thread-8;数据:55 线程:Thread-6;数据:55 线程:Thread-5;数据:55

或者我们把runnable的成员变量变为方法变量

线程:Thread-4;数据:55 线程:Thread-2;数据:55 线程:Thread-9;数据:55 线程:Thread-7;数据:55 线程:Thread-3;数据:55 线程:Thread-0;数据:55 线程:Thread-1;数据:55 线程:Thread-5;数据:55 线程:Thread-6;数据:55 线程:Thread-8;数据:55

输出都符合我们的预期。