关于Lock静态变量的方法

I'm CodeBear 2015-06-18 10:09:37
有如下的伪代码

public class Test
{
public static DataTable GetData1()
{
DataTable dt=DAL.GetData();
//一系列操作
return dt;
}

public static DataTable GetData2()
{
DataTable dt=DAL.GetData();
//一系列操作
return dt;
}
}


由于当初设计的时候没有考虑周全,导致GetData1() 和GetData2()都调用了数据访问层的同一个方法,我觉得对代码修改最小的修改的方法就是 增加一个静态变量,如


public class Store
{
public static DataTable dt;
}
public class Test
{
public static DataTable GetData1()
{
Store.dt=DAL.GetData();
//一系列操作
return dt;
}

public static DataTable GetData2()
{
DataTable dt=Store.dt;
//一系列操作
return dt;
}
}


然后,人家说 static线程是不安全的,需要锁一下,因为没有用过,想问大家一下,是不是这样锁的:


public class Store
{
public static DataTable dt;
}
public class Test
{
public static object obj;
public static DataTable GetData1()
{
DataTable dt= GetDt();
//一系列操作
}

public static DataTable GetData2()
{
DataTable dt= GetDt();
//一系列操作
}
public static DataTable GetDt()
{
lock(obj)
{
if(Store.dt!=null)
{
return Store.dt;
}else
{
Store.dt=DAL.GetData();
return Store.dt;
}
}
}
}

...全文
599 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
於黾 2015-06-23
  • 打赏
  • 举报
回复
引用 17 楼 a853495865 的回复:
我是楼主,感谢很多人回答了我的问题。可能是我对static变量的理解很模糊。 这几天我找了一些关于static变量的博文,当张三查询到内容后,把查询到的内容赋值给了一个静态变量,这个时候,李四又进行了不同的查询,这个时候,静态变量就被李四查询的内容给覆盖了。最终在页面中展示的内容就发生了错乱,张三看到的查询内容就变成了李四的查询内容了。不知道是不是这么理解的?
webform和winform的编程思路完全不同的 winform就是一个人在用,在自己的电脑内存里,不会有别的用户的数据 而webform是个网站,它天生是多线程,是服务端和客户端的通信程序 在webform里,static类型是所有线程公用的,那么就会出现所有用户的数据互相错乱的现象 所以除非是所有用户公用的数据(比如数据库连接字符串),否则不要放到static类型的变量里去
I'm CodeBear 2015-06-23
  • 打赏
  • 举报
回复
我是楼主,感谢很多人回答了我的问题。可能是我对static变量的理解很模糊。 这几天我找了一些关于static变量的博文,当张三查询到内容后,把查询到的内容赋值给了一个静态变量,这个时候,李四又进行了不同的查询,这个时候,静态变量就被李四查询的内容给覆盖了。最终在页面中展示的内容就发生了错乱,张三看到的查询内容就变成了李四的查询内容了。不知道是不是这么理解的?
足球中国 2015-06-20
  • 打赏
  • 举报
回复
多线程执行的,肯定要加锁,不加锁那成垃圾代码了。 但加锁你加在一个返回的方法上有什么意义。那不是白加了。
xinxin@chen 2015-06-19
  • 打赏
  • 举报
回复
好东西,学习学习!!
Forty2 2015-06-18
  • 打赏
  • 举报
回复
我觉得你‘加锁了的代码’和‘不加锁的代码’逻辑差别很大。 最大的问题是,‘加锁的代码’将永远返回第一次数据库查询的数据
於黾 2015-06-18
  • 打赏
  • 举报
回复
我想到了一个严重的问题 如果你一定要DataTable dt=Store.dt;这样写 改为DataTable dt=Store.dt.Copy(); 因为DataTable是引用类型,你这样赋值,并不是赋值数据,而是把静态表的引用给了实例对象 除非获取后不去操作它 否则多线程同时操作同一个静态对象,那么就有问题了 这里跟加不加lock没有任何关系
於黾 2015-06-18
  • 打赏
  • 举报
回复
程序本身没有用到多线程。 这个说法不正确 网站天生就是多线程的 难道你以为100个用户登录,他们的操作都是按顺序执行,一个等一个的吗
於黾 2015-06-18
  • 打赏
  • 举报
回复
就如SP1234所说,不加lock也没有任何问题啊,大不了有的线程多余的去访问了一次数据库,能怎么的 现在最主要的问题是,你代码冗余,但是不去解决代码冗余的问题,而是从数据来源上下手,这完全是南辕北辙,缘木求鱼啊
I'm CodeBear 2015-06-18
  • 打赏
  • 举报
回复
引用 8 楼 Z65443344 的回复:
[quote=引用 7 楼 a853495865 的回复:] [quote=引用 6 楼 Z65443344 的回复:] 由于当初设计的时候没有考虑周全,导致GetData1() 和GetData2()都调用了数据访问层的同一个方法,我觉得对代码修改最小的修改的方法就是 增加一个静态变量 我觉得你这个需求和下面的方案离题万里啊 到底要不要将GetData1的结果缓存下来给GetData2直接用,这跟里面是否调用了同一个方法没有必然联系 如果GetData2也是需要获取当前数据库中最新的数据,你就不应该用旧数据充数
GetData1()和GetDate2()所取出的数据是完全一致的。[/quote] 那么其实你就应该把这俩函数给合并成一个,而不是把它们的数据给混到一起去 你现在的问题是代码冗余,而不是数据冗余,也不是连接数据库次数过多之类的问题 除非你数据库里的数据也是根本不会变的,那么你才需要考虑把结果缓存下来,已经获取过数据就不要再去获取[/quote] 嗯,你说的没错,是代码冗余了,最好的解决方案肯定是想办法合并,但是目前时间有限,只能用其他方案去解决,, 还有我提出这个问题,并不是单纯的只想解决这个问题,而是想知道这种情况需不需要lock: 程序本身没有用到多线程。 GetData1()和GetData2()是顺序执行的,在GetData1()中对静态变量进行赋值,在GetData2()中取得静态变量的值。
於黾 2015-06-18
  • 打赏
  • 举报
回复
这就好比公司的电话号码表有2个(共享excel),内容完全一致 那么就应该去掉一个,只剩下一个,以免混乱 而不是将号码表1里的数据都复制到2里,然后1改了之后却又不去改2
於黾 2015-06-18
  • 打赏
  • 举报
回复
引用 7 楼 a853495865 的回复:
[quote=引用 6 楼 Z65443344 的回复:] 由于当初设计的时候没有考虑周全,导致GetData1() 和GetData2()都调用了数据访问层的同一个方法,我觉得对代码修改最小的修改的方法就是 增加一个静态变量 我觉得你这个需求和下面的方案离题万里啊 到底要不要将GetData1的结果缓存下来给GetData2直接用,这跟里面是否调用了同一个方法没有必然联系 如果GetData2也是需要获取当前数据库中最新的数据,你就不应该用旧数据充数
GetData1()和GetDate2()所取出的数据是完全一致的。[/quote] 那么其实你就应该把这俩函数给合并成一个,而不是把它们的数据给混到一起去 你现在的问题是代码冗余,而不是数据冗余,也不是连接数据库次数过多之类的问题 除非你数据库里的数据也是根本不会变的,那么你才需要考虑把结果缓存下来,已经获取过数据就不要再去获取
I'm CodeBear 2015-06-18
  • 打赏
  • 举报
回复
引用 6 楼 Z65443344 的回复:
由于当初设计的时候没有考虑周全,导致GetData1() 和GetData2()都调用了数据访问层的同一个方法,我觉得对代码修改最小的修改的方法就是 增加一个静态变量 我觉得你这个需求和下面的方案离题万里啊 到底要不要将GetData1的结果缓存下来给GetData2直接用,这跟里面是否调用了同一个方法没有必然联系 如果GetData2也是需要获取当前数据库中最新的数据,你就不应该用旧数据充数
GetData1()和GetDate2()所取出的数据是完全一致的。
於黾 2015-06-18
  • 打赏
  • 举报
回复
由于当初设计的时候没有考虑周全,导致GetData1() 和GetData2()都调用了数据访问层的同一个方法,我觉得对代码修改最小的修改的方法就是 增加一个静态变量 我觉得你这个需求和下面的方案离题万里啊 到底要不要将GetData1的结果缓存下来给GetData2直接用,这跟里面是否调用了同一个方法没有必然联系 如果GetData2也是需要获取当前数据库中最新的数据,你就不应该用旧数据充数
  • 打赏
  • 举报
回复
“好事者”很可能反而犹豫不决地问“那么到底这里要不要写lock呢?” 实际上写也可以,不急着写(搁置3个月以后再说)也可以。关键是你要抽出时间写个测试,来看看到底有没有什么问题。如果连测试都预先设计不出来,或者设计一个测试很费解、好像是“为了测试而测试”地而不是真实的运行时情况,那么就先不着急。
  • 打赏
  • 举报
回复
如果简写,那么可以写:
public class Store
{
    private static DataTable dt;
    public static object dtFlag = new object();

    public static DataTable GetDt()
    {
        lock (dtFlag)
        {
            if (dt == null)
                dt = DAL.GetData();
            return dt;
        }
    }
}
如果要提高一点微不足道的“性能”,可以写
public class Store
{
    private static DataTable dt;
    public static object dtFlag = new object();

    public static DataTable GetDt()
    {
        if (dt != null)
            return dt;

        lock (dtFlag)
        {
            if (dt == null)
                dt = DAL.GetData();
            return dt;
        }
    }
}
但是这种改进确实应该是“微不足道”的,它对一个应用程序(即使是非常频繁地并发访问)的用户体验基本上感觉不出来一丝一毫。 这就引出了回答上面的你在#2楼的这个问题。实际上,就算不lock,就算是你的asp.net应用恰好“同时”被两个消息处理线程执行到
if(Store.dt!=null)
而产生了所谓的“不安全”的幻象结果,那有多大事儿?只不过是可能确实是偶尔多调用了 DAL.GetData()了,这会有多大事儿呢? 我并不是说应该或者不应该lock。而是这里的代码本身是可以容许有瑕疵的,有瑕疵也没什么大不了的。除非你确实将一个由于 Store.dt=DAL.GetData(); 语句被执行了不止一次而产生的bug摆在面前。 注意,我再次强调,我此刻不是在讨论是非问题。而是“用什么方法来保证质量”。我们用“bug的存在性”来评判质量,而不是用编程的洁癖规则来评判。
bdmh 2015-06-18
  • 打赏
  • 举报
回复
如果你不对这个变量不停地修改,只是获取一个单例对象,就不用
I'm CodeBear 2015-06-18
  • 打赏
  • 举报
回复
引用 1 楼 bdmh 的回复:
你这个static变量,设置一次就不要在修改了,所以你没必要加锁,你又没用多线程异步操作
我这个是asp.net,可能同时有多个用户执行到 修改静态变量,读取静态变量的方法,这不影响吗?
bdmh 2015-06-18
  • 打赏
  • 举报
回复
你这个static变量,设置一次就不要在修改了,所以你没必要加锁,你又没用多线程异步操作
该课程由付强老师主讲,系统的、全面的、具体的讲解了java入门的知识。可以使初级的学员入门。Java入门Java的历史、Java的版本、Java的优势、软件行业前景Java开发环境搭建、编写Java入门练习虚拟机的运行机制、Java的平台无关性、虚拟机垃圾回收机制基础语法关键字、标识符、Java数据类型分类、基础数据类型、取值范围变量、常量、三种注释、生成doc文档、运算符、表达式if语句、switch语句、嵌套判断for语句、while语句、do-while语句、嵌套循环类和对象面向过程和面向对象的区别类的构成、访问修饰符、对象的内存分配this关键字、按值传递与按引用传递、对象的初始化顺序高级类特性类的继承、父子类的初始化顺序、单继承性方法的覆盖、重载、super关键字、多态、instanceof关键字、强制类型转换、static关键字、final关键字数组和枚举一维数组的应用及内存分配多维数组的应用及内存分配数组的复制、数组的按引用传递排序算法:冒泡、直接选择、插入选择、希尔、快速、归并、堆排序Arrays工具类的应用枚举类型的应用常见类的使用Object类的底层及应用、Objects类String类的底层及应用、正则表达式StringBuffer和StringBuilder的底层及应用Math类的应用、包装类的应用日期类的应用:Date、DateFormat、Calendar、LocalDateTime、Instant、LocalDate、MonthDay、ZonedDateTime、YearMonth、新旧日期转换BigInteger和BingDecimal、DecimalFormatSystem类、Scanner类抽象类和接口抽象类的规则及应用接口的规则及应用默认方法、静态方法、函数式接口、Lambda表达式异常异常的定义异常的处理:抓(try-catch-finally)、抛(throws)异常的分类、自定义异常的应用、throw关键字集合框架集合框架结构:接口、实现类Collection接口的方法、Set接口的方法、List接口的方法、Map接口的方法Array、Linked、Hash、Tree底层实现原理泛型的作用、Collections工具类、历史集合类I/O流Path类的原理及应用、Files类的原理及应用文件字节流FileInputStream的原理及应用对象类、缓冲流、数据流的原理及应用字符流的原理及应用多线程进程与线程的概念、查看线程对象Java内存模型线程的创建与启动:扩展Thread类、实现Runnable接口、实现Callable接口、线程池线程状态的转换:新建、就绪、运行、阻塞、死亡线程的调度:sleep、yield、join、interrupt、wait后台线程、定时任务线程的并发与同步、同步锁、同步块、线程安全的类Lock接口、CAS、volatile修饰符内部类成员内部类、本地内部类的应用匿名内部类的原理及引用、Lambda表达式设计模式基础设计模式概念、框架概念7大设计原则:开闭原则、依赖倒置原则、单一职责原则、接口隔离原则、迪米特原则、里氏替换原则、合成复用原则单例模式、工厂模式、模板模式、代理模式、装饰模式、适配器模式、外观模式、策略模式、观察者模式、命令模式、备忘录模式、观察者模式反射反射包Class类的使用反射获取类属性、方法、构造器通过反射创建类对象/通过反射调用方法反射的应用

110,503

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧