线程安全
线程安全包含两个方面
变量安全:进程中有多个线程在同时运行,而这些线程可能会同时运行某一段代码如果每次运行结果和单线程运行的结果是一样的。而且其他变量的值也和预期的是一样的,称为变量安全。反正,就不能叫变量安全。
线程同步:代码中的业务逻辑是一个原子性的动作,一旦分割执行就可能导致丧失其本来意义。然而在多线程环境下,运行中的线程被线程调度器暂时“叫停”的可能性随时存在的,这就给原子性的业务动作造成了潜在的危险。这时必须启用线程同步机制,即在一个线程执行完这组动作之前,其他线程不能进入这段代码。
首先介绍变量安全来看一个程序:【Main】
/** * Main.java * 版权所有(C) 2011 cuiran2001@163.com * 创建:崔冉 2011-1-13 下午03:49:47 */ package com.cayden.thread812; /** * @author 崔冉 * @version 1.0.0 * @desc */ public class Main { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Runnable accumelatora=new Accumulator(); // Runnable accumelatorb=new Accumulator(); Thread threada=new Thread(accumelatora,"ThreadA"); Thread threadb=new Thread(accumelatora,"ThreadB"); threada.start(); threadb.start(); } } class Accumulator implements Runnable { int sum=0; @Override public void run() { // TODO Auto-generated method stub // int sum=0; for(int i=1;i<=10;i++){ sum=sum+i; try{ Thread.sleep(1000); }catch (InterruptedException e) { // TODO: handle exception } System.out.println(Thread.currentThread().getName()+"/tsum="+sum); } } }
执行结果:
ThreadB sum=2 ThreadA sum=2 ThreadB sum=6 ThreadA sum=6 ThreadA sum=12 ThreadB sum=12 ThreadA sum=20 ThreadB sum=25 ThreadB sum=30 ThreadA sum=30 ThreadA sum=42 ThreadB sum=42 ThreadB sum=56 ThreadA sum=56 ThreadA sum=72 ThreadB sum=81 ThreadA sum=90 ThreadB sum=100 ThreadA sum=110 ThreadB sum=110
上面程序在单线程下市不会出现问题。但是大家看到结果就发现了问题。两个线程共用了同一个变量sum.
解决方法有两种:
第一种:舍弃“单实例,多线程”模式,而使用“多实例,多线程”模式。这种模式效率比较低,但是最接近于传统的单线程编程,基本不存在变量安全的风险。
第二种:把变量尽可能的封装在方法中,使其称为方法的内部变量。
按照第一种方法来改代码如下:
/** * Main.java * 版权所有(C) 2011 cuiran2001@163.com * 创建:崔冉 2011-1-13 下午03:49:47 */ package com.cayden.thread812; /** * @author 崔冉 * @version 1.0.0 * @desc */ public class Main { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Runnable accumelatora=new Accumulator(); Runnable accumelatorb=new Accumulator(); Thread threada=new Thread(accumelatora,"ThreadA"); Thread threadb=new Thread(accumelatorb,"ThreadB"); threada.start(); threadb.start(); } } class Accumulator implements Runnable { int sum=0; @Override public void run() { // TODO Auto-generated method stub // int sum=0; for(int i=1;i<=10;i++){ sum=sum+i; try{ Thread.sleep(1000); }catch (InterruptedException e) { // TODO: handle exception } System.out.println(Thread.currentThread().getName()+"/tsum="+sum); } } }
执行结果:
ThreadB sum=1 ThreadA sum=1 ThreadB sum=3 ThreadA sum=3 ThreadB sum=6 ThreadA sum=6 ThreadA sum=10 ThreadB sum=10 ThreadA sum=15 ThreadB sum=15 ThreadA sum=21 ThreadB sum=21 ThreadA sum=28 ThreadB sum=28 ThreadB sum=36 ThreadA sum=36 ThreadA sum=45 ThreadB sum=45 ThreadA sum=55 ThreadB sum=55
按照第二种方法代码如下:
/** * Main.java * 版权所有(C) 2011 cuiran2001@163.com * 创建:崔冉 2011-1-13 下午03:49:47 */ package com.cayden.thread812; /** * @author 崔冉 * @version 1.0.0 * @desc */ public class Main { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Runnable accumelatora=new Accumulator(); // Runnable accumelatorb=new Accumulator(); Thread threada=new Thread(accumelatora,"ThreadA"); Thread threadb=new Thread(accumelatora,"ThreadB"); threada.start(); threadb.start(); } } class Accumulator implements Runnable { // int sum=0; @Override public void run() { // TODO Auto-generated method stub int sum=0; for(int i=1;i<=10;i++){ sum=sum+i; try{ Thread.sleep(1000); }catch (InterruptedException e) { // TODO: handle exception } System.out.println(Thread.currentThread().getName()+"/tsum="+sum); } } }
执行结果:
ThreadA sum=1 ThreadB sum=1 ThreadA sum=3 ThreadB sum=3 ThreadB sum=6 ThreadA sum=6 ThreadB sum=10 ThreadA sum=10 ThreadA sum=15 ThreadB sum=15 ThreadB sum=21 ThreadA sum=21 ThreadA sum=28 ThreadB sum=28 ThreadA sum=36 ThreadB sum=36 ThreadA sum=45
<!--EndFragment-->
<!--EndFragment-->
<!--EndFragment-->