抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

无状态方法

线程安全

同事经常跟我强调线程安全的重要性,比如下面这段代码,id是一个静态成员变量,被所有Student类的对象共享,在多线程环境下可能会造成不确定行为

class Student
{
private:
static int id = 0;
public:
int getId()
{
return id;
}
}
int Student::id = 0;

我们可以加入一个锁以实现线程安全,std::lock_guard会通过其生命周期创建销毁锁

class Student
{
private:
static int id = 0;
static std::mutex id_mutex;
public:
int getId()
{
std::lock_guard<std::mutex> lock(id_mutex);
return id;
}
}
int Student::id = 0;

无状态方法

然后同事又跟我介绍了无状态方法(Stateless),即计算中不依赖先前的状态或上下文的方法。比如stl中大量的非成员函数,他们大多都是无状态方法

// 这种非成员函数是无状态的
int adder(int a, int b)
{
return a + b;
}

int main(int argc, char **argv){
std::cout << adder(2, 3);
return 0;
}
// 通过重载()运算符来实现adder
class Adder{
public:
Adder(int c){ this->c = c; }
int operator()(int a, int b){
return a+b+c;
}
private:
int c;
};

int main(int argc, char **argv){
Adder adder(1);
std::cout << adder(2, 3);
return 0;
}

一般而言,无状态方法只要输入是确定的,输出一般是可预料的(内部使用random相关函数的输出总体也是有期望的)

与无状态方法对应的是有状态方法(Stateful),比如一些读资源函数,我传入一个指针、Handle、索引,返回的结果取决于资源状态,输出的结果是不确定的。有状态方法一般要注意线程安全问题、空指针、索引越界等问题

// 不好的设计,因为getCurrentDateText的结果与format的状态有关
// 尽管这样设计性能更好(不频繁创建新对象),一般也没人改format
public class Sample
{
private static final DateFormat format = new SimpleDateFormat("yyyy.MM.dd");

public String getCurrentDateText()
{
return format.format(new Date());
}
}
// 无状态方法,线程安全
public class Sample
{
public String getCurrentDateText() {
return new SimpleDateFormat("yyyy.MM.dd").format(new Date());
}
}

参考

无状态方法

评论