【LSP】java安全编码指南之:lock和同步的正确使用

编程开发   © 文章版权由 admin 解释,禁止匿名转载

#楼主# 2020-10-11

简介
在java多线程环境中,lock和同步是我们一定会使用到的功能。那么在java中编写lock和同步相关的代码之后,需要注意哪些问题呢?一起来看看吧。

使用private final object来作为lock对象
一般来说我们在做多线程共享对象的时候就需要进行同步。java中有两种同步方式,第一种就是方法同步,第二种是同步块。

如果我们在实例方法中使用的是synchronized关键字,或者在同步块中使用的是synchronized(this),那么会以该该对象的实例作为monitor,我们称之为intrinsic lock。

如果有恶意代码恶意获取该对象的锁并且释放,那么我们的系统将不能及时响应正常的服务,将会遭受到DOS攻击。

解决这种问题的方法就是使用private final object来作为lock的对象。因为是private的,所以恶意对象无法获取到该对象的锁,从而避免了问题的产生。

如果是在类方法(static)中使用了synchronized关键字,那么将会以这个class对象作为monitor。这种情况下,恶意对象可以通过该class的子类或者直接获取到该class,然后通过调用getClass()获取到class对象,从而进行加锁操作,让正常服务无法获取到锁。

所以,我们推荐使用private final object来作为lock对象。

下面举几个例子来说明:

我们看第二种写法:

public Object lock = new Object();

public void doSomething2(){
synchronized (lock){
//do something
}
}
上面的例子中,我们同步了一个public对象,但是因为该对象是public的,所以恶意程序完全可以访问该public字段,并且永久获得这个对象的monitor,从而产生DOS。

再看下面的一个例子:

private volatile Object lock2 = new Object();

public void doSomething3() {
synchronized (lock2) {
// do something
}
}

public void setLock2(Object lockValue) {
lock2 = lockValue;
}
上面的例子中,我们定义了一个private的lock对象,并且使用它来为doSomething3方法加锁。

虽然是private的,但是我们提供了一个public的方法来对该对象进行修改。所以也是有安全问题的。

正确的做法是使用private final Object:

private final Object lock4= new Object();

public void doSomething4() {
synchronized (lock4) {
// do something
}
}
我们再考虑一下静态方法的情况:

public static synchronized void doSomething5() {
// do something
}

synchronized (SynObject.class) {
while (true) {
Thread.sleep(10000);
}
}
上面定义了一个public static的方法,从而锁定的是class对象,恶意代码可以恶意占有该对象的锁,从而导致DOS。

不要synchronize可被重用的对象
之前我们在讲表达式规则的时候,提到了封装类对象的构建原则:

对于Boolean和Byte来说,如果直接从基础类值构建的话,也是同一个对象。

而对于Character来说,如果值的范围在\u0000 to \u007f,则属于同一个对象,如果超出了这个范围,则是不同的对象。

对于Integer和Short来说,如果值的范围在-128 and 127,则属于同一个对象,如果超出了这个范围,则是不同的对象。

举个例子:

Boolean boolA=true;
Boolean boolB=true;
System.out.println(boolA==boolB);

成为第一个回答人

评论

登录后才可发表内容
  • 主题

    124

  • 帖子

    0

  • 关注者

    0

Copyright © 2019 凯特网.   Powered by HYBBS 2.3.4  

Runtime:35.2144s Mem:2054Kb