基础才是重中之重~关于ThreadStatic和Quartz的一点渊源
ThreadStatic
ThreadStatic是C#里的一个特性,它可以让你的字段在一个线程里有效,但你不能控制这个字段在何时被回收,即如果声明一个int32的字段为ThreadStatic,然后你为它赋值时为100,那么它什么被恢复成默认值0,我们不得而知,这在开发时,我们可能只有手动将它设为0才行,比较难看,但也没办法,谁让咱们用了ThreadStatic呢,被声明为ThreadStatic之后,已经证明这个字段是静态化的,只不过它是被局限在一个线程内的。
Quartz
Quartz是一个任务调度框架,起源于java,它目前被广泛的使用在各种后台处理数据的场合,像一些统计数据,推送数据,消息数据等,它可以大大降低前端服务器的并发压力,并且Quartz的管理界面也有很多,直接nuget安装即可,在这些产品中最知名的应该就是CrystalQuartz了,它可以在WEB界面中管理咱们的JOB项目!
日志系统Lind.DDD.Logger
Logger本来是Lind框架的一个日志组件,它是最低层的组件,是其它组件的基础,也被用到其它的业务系统里,而其中一个Quartz组件里,使用Logger时提出了一个问题,就是如何根据job去自动建立日志目录,让每个JOB都有自己的目录,这样在分析日志时还是很有必要的。
希望看到的结果如图
aaarticlea/png;base64,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" alt="" />
测试用的两个Job
public class Hello_Job : JobBase
{ protected override void ExcuteJob()
{ Console.WriteLine("Hello Job方法:" + Thread.CurrentThread.ManagedThreadId);
Lind.DDD.Logger.LoggerFactory.Instance.Logger_Info("Hello Job日志!");
}
} public class Hi_Job : Lind.DDD.QuartzJob.JobBase
{ protected override void ExcuteJob()
{ Console.WriteLine("Hi Job!" + Thread.CurrentThread.ManagedThreadId);
Lind.DDD.Logger.LoggerFactory.Instance.Logger_Info("Hi Job!"); }
}
JobBase做于所有Job的基类存在,它主要有自己的抽象方法和IJob的接口方法,其中抽象方法由字类Job自己去实现,去实现自己的业务逻辑;而IJob方法由Quartz框架去调用,并在方法中自己调用了抽象方法的内容,大致代码如下
[DisallowConcurrentExecution()]
public abstract class JobBase : IJob
{ #region IJob 成员
/// <summary>
/// Job主方法
/// </summary>
/// <param name="context"></param>
public void Execute(IJobExecutionContext context)
{
Lind.DDD.Logger.LoggerFactory.Instance.SetPath(this.GetType().Name);
ExcuteJob();
Console.WriteLine(DateTime.Now.ToString() + "{0}这个Job开始执行", context.JobDetail.Key.Name);
} #endregion /// <summary>
/// Job具体类去实现自己的逻辑
/// </summary>
protected abstract void ExcuteJob();
}
日志组件中的字段使用了ThreadStatic
对日志文件分文件夹存储,主要在日志组件中使用ThreadStatic来实现的,代码主要如下
/// <summary>
/// 每个子类初始时都执行基类这个构造,初始化当前路径
/// </summary>
public LoggerBase()
{
FileUrl = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LoggerDir");
}
/// <summary>
/// 日志文件地址
/// 优化级为mvc方案地址,网站方案地址,console程序地址
/// </summary>
[ThreadStatic]
static protected string FileUrl;
#region ILogger 成员
public void SetPath(string path)
{
if (!string.IsNullOrWhiteSpace(path))
{
FileUrl = FileUrl + "\\" + path;
}
}
#endregion
对于FileLogger这个文件日志实现类来说,它要做的是,在写完文件流之后,要把FileUrl这个字段从新赋值,因为我们不知道这个字符串什么时候被清空!
lock (objLock)//防治多线程读写冲突
{
using (System.IO.StreamWriter srFile = new System.IO.StreamWriter(filePath, true))
{
srFile.WriteLine(string.Format("{0}{1}{2}"
, DateTime.Now.ToString().PadRight()
, ("[ThreadID:" + Thread.CurrentThread.ManagedThreadId.ToString() + "]").PadRight()
, message));
srFile.Close();
srFile.Dispose();
}
}
//清除当前的路径
FileUrl = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LoggerDir");
上面的问题,我也是找了很久,因为总是找不到测试不成功的原因,最后想到了ThreadStatic特性的声明周期,算是找到根源了,呵呵!
建议大家看看C#的《对象的生与死》!
基础才是重中之重~关于ThreadStatic和Quartz的一点渊源的更多相关文章
- WPF MVVM UI分离之《交互与数据分离》 基础才是重中之重~delegate里的Invoke和BeginInvoke 将不确定变为确定系列~目录(“机器最能证明一切”) 爱上MVC3系列~全局异常处理与异常日志 基础才是重中之重~lock和monitor的区别 将不确定变成确定~我想监视我的对象,如果是某个值,就叫另一些方法自动运行 将不确定变成确定~LINQ DBML模型可以对
WPF MVVM UI分离之<交互与数据分离> 在我们使用WPF过程中,不可避免并且超级喜欢使用MVVM框架. 那么,使用MVVM的出发点是视觉与业务逻辑分离,即UI与数据分离 诸如下 ...
- 基础才是重中之重~方法override详解
回到 目录 之所以写这篇文章,完全是因为这次代码审核,这次代码审核过程当中,出现了很多我认为基础知识不够扎实的问题,所以,打算把它们记录下来,共大家分享. 方法的override,即方法的覆写或者重写 ...
- 基础才是重中之重~ConcurrentDictionary让你的多线程代码更优美
回到目录 ConcurrentDictionary是.net4.0推出的一套线程安全集合里的其中一个,和它一起被发行的还有ConcurrentStack,ConcurrentQueue等类型,它们的单 ...
- 基础才是重中之重~stream和byte[]的概念与转化
回到目录 多看几篇 之所以写这篇文章完全是因为最近在研究FastDFS这个分布式的文件存储系统,当然这不是我第一次研究它了,就像我们去看一本书,我们不会只看一篇,而是一次次,一篇篇,每看一次会有新的收 ...
- 基础才是重中之重~理解linq中的groupby
linq将大部分SQL语句进行了封装,这使得它们更加面向对象了,对于开发者来说,这是一件好事,下面我从基础层面来说一下GroupBy在LINQ中的使用. 对GroupBy的多字段分组,可以看我的这篇文 ...
- 基础才是重中之重~lock和monitor的区别
回到目录 Monitor的介绍 1.Monitor.Enter(object)方法是获取锁,Monitor.Exit(object)方法是释放锁,这就是Monitor最常用的两个方法,当然在使用过程中 ...
- C# 基础才是重中之重~对象的生与死
为何要写 之所以写这篇文章,完全是因为学生们在实际开发中遇到的问题,一个对象占用的内存空间总不被释放,导致系统内存不断攀升,其最主要原因是我们对“对象的生与死”不清楚,或者从来没有认真去考虑过这件事, ...
- 基础才是重中之重~Emit动态构建方法(参数和返回值)
回到目录 对于Emit我们知道它的可以动态构建程序集,类型,方法,属性等,或者说只要手动使用C#创建的东西使用Emit也都可以动态创建它们,Emit由于它的特别之处,所以在很多领域得到了广泛的应用,像 ...
- 基础才是重中之重~LazyInitializer.EnsureInitialized对属性实现化的性能优化
回到目录 LazyInitializer.EnsureInitialized是frameworks4.0引入的新东西,实现对属性延时初始化的功能,它作用在System.Threading命名空间下,所 ...
随机推荐
- laravel的延迟消息队列
laravel的延迟消息队列 这篇来自于看到朋友转的58沈剑的一篇文章:1分钟实现"延迟消息"功能(http://mp.weixin.qq.com/s?__biz=MjM5ODYx ...
- APIJSON-以坚持和偏执,回敬傲慢和偏见
APIJSON简介: APIJSON是一种JSON传输结构协议. 客户端可以定义任何JSON结构去向服务端发起请求,服务端就会返回对应结构的JSON字符串,所求即所得. 一次请求任意结构任意数据,方便 ...
- JS清除DIV的选中状态
var clearSlct = "getSelection" in window ? function () { window.getSelection().removeAllRa ...
- 【Python系列】Python自动发邮件脚本-html邮件内容
缘起 这段时间给朋友搞了个群发邮件的脚本,为了防止进入垃圾邮件,做了很多工作,刚搞完,垃圾邮件进入率50%,觉得还不错,如果要将垃圾邮件的进入率再调低,估计就要花钱买主机了,想想也就算了,先发一个月, ...
- Authorization user to use specifical database
DENY VIEW any DATABASE to PUBLIC;ALTER AUTHORIZATION ON DATABASE::Best TO Best
- CSS与HTML5响应式图片
随着 Retina 屏幕的逐渐普及,网页中对图片的适配要求也越来越高.如何让图片在放大了两倍的 Retina 屏幕显示依然清晰,曾经一度困扰着网页开发者,好在 CSS3 与 HTML5 已经着力在改变 ...
- Java变量和对象的作用域
大多数程序设计语言都提供了"作用域"(Scope)的概念. 对于在作用域里定义的名字,作用域同时决定了它的"可见性"以及"存在时间".在C, ...
- jenkins+SVN配置
开发项目,版本控制必不可少,我用的版本控制软件为SVN,那么如何把jenkins和SVN结合,使得SVN源码一有上传更新,jenkins就马上构建项目呢?下面说一下配置过程 1) ...
- Linux 搭建svn版本库
一.安装svn服务器端yum install subversion 从镜像下载安装svn服务器端 如果后面执行“svnadmin create /usr/local/svn/sunny”提示 ...
- 在 WPF 中使用 Path 路径
在 WPF 中总会修改 Button 的 Style,比如一个自定义的 Close 按钮.刚入门的可能会用一张 PNG 格式的图片来做这个按钮的 Icon,但这个是不优雅的.而且你要改的时候还得去操作 ...