可重入(线程安全)

可重入(reentrant)的类或方法,又称线程安全(threadsafe)的类或方法。
是指一个类或方法,在多个线程里同时调用(并发调用)的时候,其功能仍然正常。

如在并发调用时功能出错的方法(线程不安全的Thread Unsafe)
例如,下面的方法用于求和
int sum(int n){
	int result=0;
	for(int i=1;i<=n;i++){
		result+=i;
	}
	return result;
}

  我们的代码:

class Add{
	static int sum(int n){
		int result=0;
		for(int i=1;i<=n;i++){
			result+=i;
		}
		return result;
	}
}
public class Demo {
	public static void main(String[] args) {
		new Thread(new Runnable(){
			@Override
			public void run(){
				int n=500;
				while(n--!=0){
					int ret=Add.sum(100);
					if(ret!=5050){System.out.println(Thread.currentThread().getName()+" "+ret);}
				}
			}
		},"t1").start();
		new Thread(new Runnable(){
			@Override
			public void run(){
				int n=500;
				while(n--!=0){
					int ret=Add.sum(100);
					if(ret!=5050){System.out.println(Thread.currentThread().getName()+" "+ret);}
				}
			}
		},"t2").start();
	}
}

  运行时,方法sum始终能进行对1~100的求和,得出5050。所以是线程安全的。

我们从反面验证线程不安全的

将以上代码修改:

class Number{public static int result;}
class Add{
	static int sum(int n){ //借助全局变量,此方法在单线程时是没有任何问题的(可运行测试)
		Number.result=0;
		for(int i=1;i<=n;i++){
			Number.result+=i;
		}
		return Number.result;
	}
}
public class Demo {
	public static void main(String[] args) {
		new Thread(new Runnable(){
			@Override
			public void run(){
				int n=500;
				while(n--!=0){
					int ret=Add.sum(100);
					if(ret!=5050){System.out.println(Thread.currentThread().getName()+" "+ret);}
				}
			}
		},"t1").start();
		new Thread(new Runnable(){
			@Override
			public void run(){
				int n=500;
				while(n--!=0){
					int ret=Add.sum(100);
					if(ret!=5050){System.out.println(Thread.currentThread().getName()+" "+ret);}
				}
			}
		},"t2").start();
	}
}

当计算结果不是5050时我们打印输出  

运行如图:

可重入的方法
判断一个方法是否是可重入的:
(1)在单线程的情况下,该方法表现正常
如果单线程也不行,说明这个方法写错了
(2) 在多线程并发调用此方法时,该方法仍然表现正常。
则称为该方法是可重入的。

以下方法很可能是不可重入的:
(1)一个全局方法(写在类体之外的方法)
如果它借助于全局对象来实现,并且有写操作,那么就是不可重入的。
(2) 一个类的成员方法
它访问并修改了成员变量,那么一般情况下它就是不可重入的。

如何将不可重入的方法,改为可重入的?
(1) 不借助外部的变量来实现
尽量用本方法内定义的局部变量来实现。
或者在本方法动态创建对象
(没有外部依赖,不操作外部变量)
(2) 实在不行的话,加上互斥锁控制

class Number{public static int result;}
class Add{
	static synchronized int sum(int n){ //synchronized将不可重入修改为可重入(加锁)
		Number.result=0;
		for(int i=1;i<=n;i++){
			Number.result+=i;
		}
		return Number.result;
	}
}

  

原文地址:https://www.cnblogs.com/mengxinrenyu/p/8097865.html