厚积薄发,丰富的公用类库积累,助你高效进行系统开发(11)---各种线程相关操作类

俗话说,一个好汉十个帮,众人拾柴火焰高等都说明一个道理,有更多的资源,更丰富的积累,都是助你走向成功,走向顶峰的推动力。

本篇的公用类库的介绍主题是程序开发中多线程操作环境中,常用到的线程相关类,本篇随笔介绍包含单件创建辅助类、Timer定时器、委托处理辅助类、队列的线程处理服务辅助类、可以取消执行操作的线程池辅助类、线程池辅助类、线程辅助类等对象,这些辅助类覆盖了多线程开发中绝大多数的应用。良好的封装及操作,给我们提供非常方便、高效的线程操作处理。

本篇继续继续整理优化已有的共用类库,并继续发表随笔介绍公用类库的接口方法以及详细使用操作,力求给自己继续优化,积攒更丰富的公用类库资源,加深了解的同时,也给大家展现公用类库好的方面。

**1、单件操作辅助类 Singleton。 **
实现效果

  1. 本辅助类主要是用来方便实现类对象的单件实例操作,减少重复写单件实现代码的繁琐,简化类的代码。
    2)创建一个类对象的单件实例,类对象的构造函数不能为Public修饰符的,一般为private。

实现代码
1)辅助类提供的方法源码如下所示:

/// <summary>    
/// 创建一个类对象的单件实例,类对象的构造函数不能为Public修饰符的,一般为private。    
/// </summary>    
/// <typeparam name="T">待创建的对象类</typeparam>
public static class Singleton<T> where T : class   
{    
    static volatile T _instance;    
    static object _lock = new object();    
   
    static Singleton()    
    {    
    }    
   
    /// <summary>    
    /// 创建/获取一个可以new的类对象的单件实例    
    /// </summary>
    public static T Instance    
    {    
        get   
        {    
            if (_instance == null)    
                lock (_lock)    
                {    
                    if (_instance == null)    
                    {    
                        ConstructorInfo constructor = null;    
   
                        try   
                        {    
                            // 构造函数不包含public修饰符的    
                            constructor = typeof(T).GetConstructor(BindingFlags.Instance |    
                                          BindingFlags.NonPublic, null, new Type[0], null);    
                        }    
                        catch (Exception exception)    
                        {    
                            throw new InvalidOperationException(exception.Message, exception);    
                        }    
   
                        if (constructor == null || constructor.IsAssembly)    
                        {    
                            throw new InvalidOperationException(string.Format("在'{0}'里面没有找到private或者protected的构造函数。", typeof(T).Name));    
                        }    
   
                        _instance = (T)constructor.Invoke(null);    
                    }    
                }    
   
            return _instance;    
        }    
    }  

2)辅助类Singleton的使用例子代码如下所示

/// <summary>    
/// 单件测试类    
/// </summary>
public class TestSingletonClass    
{    
    /// <summary>    
    /// 私有构造函数    
    /// </summary>
    private TestSingletonClass()    
    {    
    }    
   
    public void ShowMessage()    
    {    
        MessageUtil.ShowTips("单件实例测试函数");    
    }    
}    
   
private void btnSingleton_Click(object sender, EventArgs e)    
{    
    //单件辅助类使用代码    
    Singleton<TestSingletonClass>.Instance.ShowMessage();    
}

如果没有使用单件辅助类,那么单件的测试类将会需要这样书写,很明显多了很多行代码,如果每个想单件处理的类都要这样写,代码量还是很可观的,而且比较繁琐。

/// <summary>    
/// 单件测试类    
/// </summary>
public class TestSingletonClass    
{    
    private static TestSingletonClass m_Instance;    
   
    /// <summary>    
    /// 单件实例    
    /// </summary>
    public static TestSingletonClass Instance    
    {    
        get   
        {    
            if (m_Instance == null)    
            {    
                m_Instance = new TestSingletonClass();    
            }    
            return m_Instance;    
        }    
    }    
   
    /// <summary>    
    /// 私有构造函数    
    /// </summary>
    private TestSingletonClass()    
    {    
    }    
   
    public void ShowMessage()    
    {    
        MessageUtil.ShowTips("单件实例测试函数");    
    }    
}  

**2、定期执行某些任务的定时器辅助类Timer。 **
实现效果

  1. 本辅助类主要是用来方便实现定时器辅助类,功能和另外一个定时器辅助类TimerHelper差不多。
    2) 定时器操作,都通过对象锁以及在运行处理事件的时候,动态改变间隔事件为无限等待,处理完成后修改为间隔时间的方式,实现对定时器的正常、安全执行,不会发生运行一半又跳到下一个的处理过程中。
    3).NET提供了3种定时器实现,他们的特点如下所示。该Timer辅助类是基于Threading.Timer的定时器实现。

实现代码

1)辅助类提供的方法接口如下所示:

#region 事件或属性    
   
/// <summary>    
/// 按定时器周期定期引发的事件    
/// </summary>
public event EventHandler Elapsed;    
   
/// <summary>    
/// 定时器任务间隔(毫秒)    
/// </summary>
public int Period { get; set; }    
   
/// <summary>    
/// 指示是否在方法开始的时候,启动定时器Elapsed事件一次。默认为false。    
/// </summary>
public bool RunOnStart { get; set; }   
  
#endregion   
  
#region 构造函数    
   
/// <summary>    
/// 创建一个定时器    
/// </summary>    
/// <param name="period">定时器间隔 (毫秒)</param>
public Timer(int period)    : this(period, false)    
   
/// <summary>    
/// 创建一个定时器    
/// </summary>    
/// <param name="period">定时器间隔 (毫秒)</param>    
/// <param name="runOnStart">指示是否在方法开始的时候,启动定时器Elapsed事件一次</param>
public Timer(int period, bool runOnStart)   
  
#endregion   
  
#region 方法    
   
/// <summary>    
/// 启动定时器    
/// </summary>
public void Start()    
   
/// <summary>    
/// 停止定时器    
/// </summary>
public void Stop()    
   
/// <summary>    
/// 等待定时器停止    
/// </summary>
public void WaitToStop()   
  
  
#endregion  

2)辅助类Timer 的使用例子代码如下所示

private void btnTimer_Click(object sender, EventArgs e)    
{    
    WHC.OrderWater.Commons.Threading.Timer timer = new WHC.OrderWater.Commons.Threading.Timer(1000, true);    
    timer.Elapsed += new EventHandler(timer_Elapsed);    
    timer.Start();    
}    
   
void timer_Elapsed(object sender, EventArgs e)    
{    
    if (!this.InvokeRequired)    
        return;    
   
    this.Invoke(new MethodInvoker(delegate()    
    {    
        this.btnTimer.Text = DateTime.Now.ToLongTimeString();    
    }));    
}  

3、定时器辅助类TimerHelper,可指定运行间隔、延迟启动时间等操作。

实现效果

  1. 本辅助类主要是用来方便实现定时器辅助类,可指定运行间隔、延迟启动时间等操作。功能和另外一个定时器辅助类Timer差不多。

2)定时器操作,都通过对象锁以及在运行处理事件的时候,动态改变间隔事件为无限等待,处理完成后修改为间隔时间的方式,实现对定时器的正常、安全执行,不会发生运行一半又跳到下一个的处理过程中。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>    
/// 定时器执行操作的函数原型    
/// </summary>
public delegate void TimerExecution();    
   
/// <summary>    
/// 定时器执行时调用的操作    
/// </summary>
public event TimerExecution Execute;    
   
/// <summary>    
/// 创建一个指定时间间隔的定时器,并在指定的延迟后开始启动。(默认间隔为100毫秒)    
/// </summary>
public TimerHelper()    
   
/// <summary>    
/// 创建一个指定时间间隔的定时器,并在指定的延迟后开始启动。    
/// </summary>    
/// <param name="interval">定时器执行操作的间隔时间(毫秒)</param>    
/// <param name="startDelay">指定的延迟时间(毫秒)</param>
public TimerHelper(long interval, int startDelay)    
   
/// <summary>    
/// 创建一个指定时间间隔的定时器    
/// </summary>    
/// <param name="interval">定时器执行操作的间隔时间(毫秒)</param>    
/// <param name="start">是否启动</param>
public TimerHelper(long interval, bool start)    
   
/// <summary>    
/// 启动定时器并指定延迟时间(毫秒)    
/// </summary>    
/// <param name="delayBeforeStart">指定延迟时间(毫秒)</param>
public void Start(int delayBeforeStart)    
   
/// <summary>    
/// 立即启动定时器    
/// </summary>
public void Start()    
   
/// <summary>    
/// 暂停定时器    
/// 注意:运行中的线程不会被停止    
/// </summary>
public void Pause()    
   
/// <summary>    
/// 停止定时器    
/// 注意:运行中的线程不会被停止    
/// </summary>
public void Stop()    
   
/// <summary>    
/// 定时器的处理时间    
/// </summary>    
/// <param name="obj"></param>
public void Tick(object obj)    
   
/// <summary>    
/// 定时器的状态    
/// </summary>
public TimerState State    
   
/// <summary>    
/// 获取或设置定时器的运行间隔    
/// </summary>
public long Interval  

2)辅助类TimerHelper的使用例子代码如下所示

public FrmNewHouse()    
    {    
        InitializeComponent();    
   
        if (!this.DesignMode)    
        {    
            this.winGridViewPager1.OnPageChanged += new EventHandler(winGridViewPager1_OnPageChanged);    
            this.winGridViewPager1.OnStartExport += new EventHandler(winGridViewPager1_OnStartExport);    
            this.winGridViewPager1.OnRefresh += new EventHandler(winGridViewPager1_OnRefresh);    
            this.winGridViewPager1.OnGridViewMouseDoubleClick += new EventHandler(winGridViewPager1_OnGridViewMouseDoubleClick);    
            this.winGridViewPager1.ShowLineNumber = true;    
            this.winGridViewPager1.PagerInfo.PageSize = 20;    
            this.winGridViewPager1.BestFitColumnWith = true;    
            this.winGridViewPager1.AppendedMenu = this.contextMenuStrip1;    
            this.winGridViewPager1.gridView1.RowCellStyle += new DevExpress.XtraGrid.Views.Grid.RowCellStyleEventHandler(gridView1_RowCellStyle);    
   
            //使用定时器,定时刷新窗体的数据,并提示客户更新情况    
            int interval = Portal.gc.GetRefreshSecond();//获取定时间隔时间    
            TimerHelper timer = new TimerHelper(interval, true);    
            timer.Execute += new TimerHelper.TimerExecution(timer_Execute);    
        }    
    }    
        
    //通过Invoke来实现跨线程间的调用    
    void timer_Execute()    
    {    
        if (!this.InvokeRequired)    
            return;    
   
        this.Invoke(new MethodInvoker(delegate()    
        {    
            NotifyNewHouse();    
        }));    
    }  

4、提供一个队列的线程处理服务辅助类 QueueServer。

实现效果

  1. 本辅助类主要是用来方便实现提供一个队列的线程处理服务操作。QueueServer是一个先入先出(FIFO)的队列处理服务。

实现代码

1)辅助类提供的方法接口如下所示:

#region  属性方法    
   
/// <summary>    
/// 是否是背景线程    
/// </summary>
public bool IsBackground    
   
/// <summary>    
/// 执行队列    
/// </summary>
public T[] Items    
   
/// <summary>    
/// 队列数量    
/// </summary>
public int QueueCount    
   
/// <summary>    
/// 将对象加到队列结尾    
/// </summary>    
/// <param name="item"></param>
public void EnqueueItem(T item)    
   
/// <summary>    
/// 清除队列    
/// </summary>
public void ClearItems()   
  
#endregion   
  
#region 线程处理    
   
/// <summary>    
/// 处理单个元素    
/// </summary>    
/// <param name="item">元素项目</param>
protected virtual void OnProcessItem(T item)    
   
/// <summary>    
/// 处理函数    
/// </summary>
public event Action<T> ProcessItem;   
  
#endregion 

2)辅助类QueueServer的使用例子代码如下所示

 private void btnQueneServer_Click(object sender, EventArgs e)    
    {    
        QueueServer<PreDataInfo> queueServer = new QueueServer<PreDataInfo>();    
        queueServer.IsBackground = true;    
        queueServer.ProcessItem += new Action<PreDataInfo>(queueServer_ProcessItem);    
   
        //循环入队    
        for (int i = 0; i < 100; i++)    
        {    
            queueServer.EnqueueItem(new PreDataInfo(i.ToString(), DateTime.Now.ToString()));    
            Thread.Sleep(10);    
        }    
    }    
   
    /// <summary>    
    /// 处理每个出队的操作    
    /// </summary>
    void queueServer_ProcessItem(PreDataInfo obj)    
    {    
        Console.WriteLine("{0} : {1}", obj.Key, obj.Data);    
    }    
}    
   
public class PreDataInfo    
{    
    public string Key;    
    public string Data;    
   
    public PreDataInfo()    
    {    
    }    
   
    public PreDataInfo(string key, string data)    
    {    
        this.Key = key;    
        this.Data = data;    
    }    
}  

5、可以取消执行操作的线程池辅助类 AbortableThreadPool。

实现效果

  1. 本辅助类主要是用来方便实现可以取消执行操作的线程池操作。

2)AbortableThreadPool线程辅助类可以使用常用的多线程处理环境中,也可以使用在有些在运行过程中可能需要取消的线程处理环境中。

实现代码

1)辅助类提供的方法接口如下所示:

 /// <summary>        
 /// 把执行操作放到队列中。当线程池的线程可用的时候,方法执行。        
 /// </summary>        
 /// <param name="callback">一个代表将要执行方法的WaitCallback对象</param>
 public static WorkItem QueueUserWorkItem(WaitCallback callback)        
         
 /// <summary>        
 /// 把执行操作放到队列中,并指定了一个对象,它包含将要执行方法的数据。        
 /// 当线程池的线程可用的时候,方法执行。        
 /// </summary>        
 /// <param name="callback">一个代表将要执行方法的WaitCallback对象</param>        
 /// <param name="state">一个对象,它包含将要执行方法的数据</param>
 public static WorkItem QueueUserWorkItem(WaitCallback callback, object state)        
       
 /// <summary>        
 /// 取消指定的队列中的工作项。        
 /// </summary>        
 /// <param name="item">线程池中取消的项目</param>        
 /// <param name="allowAbort">如果设置为<see langword="true"/>则允许终止线程</param>        
 /// <returns>项目队列的状态</returns>
 public static WorkItemStatus Cancel(WorkItem item, bool allowAbort)        
       
 /// <summary>        
 /// 获取指定队列中工作项的状态        
 /// </summary>        
 /// <param name="item">线程池中工作项</param>        
 /// <returns>工作项的状态</returns>
 public static WorkItemStatus GetStatus(WorkItem item)      
   
      /// <summary>    
      /// 取消所有任务    
      /// </summary>    
      /// <param name="allowAbort">线程是否终止</param>
      public static void CancelAll(bool allowAbort)    
   
      /// <summary>    
      /// 类似Thread.Join,等待AbortableThreadPool执行完成    
      /// </summary>
      public static void Join()    
   
      /// <summary>    
      /// 类似Thread.Join,等待AbortableThreadPool执行完成    
      /// </summary>    
      /// <param name="millisecondsTimeout">等待的毫秒数</param>    
      /// <returns></returns>
      public static  bool Join(int millisecondsTimeout)    
   
      /// <summary>    
      /// 类似Thread.Join,等待AbortableThreadPool执行完成    
      /// </summary>    
      /// <param name="timeout">等待的时间范围</param>    
      /// <returns></returns>
      public static bool Join(TimeSpan timeout)    
   
      /// <summary>    
      /// 在队列中,还未执行处理的数量    
      /// </summary>
      public static int QueueCount    
   
      /// <summary>    
      /// 在执行中的线程数量    
      /// </summary>
      public static int WorkingCount  

2)辅助类AbortableThreadPool的使用例子代码如下所示

private void btnAbortableThreadPool_Click(object sender, EventArgs e)    
{    
    Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));    
        
    WorkItem workItem1 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));    
    Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));    
        
    WorkItem workItem2 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));    
    WorkItem workItem3 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));    
    WorkItem workItem4 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));    
    WorkItem workItem5 = AbortableThreadPool.QueueUserWorkItem(new WaitCallback(Test));    
    Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));    
    Thread.Sleep(1000);    
        
    Console.WriteLine(AbortableThreadPool.Cancel(workItem1, false));    
    Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));    
    Thread.Sleep(1000);    
        
    Console.WriteLine(AbortableThreadPool.Cancel(workItem1, true));    
    Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));    
    Thread.Sleep(1000);    
        
    //AbortableThreadPool.CancelAll(true);//可取消所有任务    
    AbortableThreadPool.Join(); //等待所有任务退出    
    Console.WriteLine(string.Format("QueueCount:{0},WorkingCount:{1}", AbortableThreadPool.QueueCount, AbortableThreadPool.WorkingCount));    
}    
   
static void Test(object state)    
{    
    int i = 100;    
    while (i-- > 0)    
    {    
        Console.WriteLine(i);    
        Thread.Sleep(new Random((int)DateTime.Now.Ticks).Next(100));    
    }    
}  

6、委托处理辅助类DelegateHelper。

实现效果

  1. 本辅助类主要是用来方便实现委托的处理。

2)使用委托处理辅助类DelegateHelper,可以快速执行或者取消一些委托方法的执行。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>    
/// 执行委托操作    
/// </summary>    
/// <param name="target">目标委托对象</param>    
/// <param name="args">参数</param>
public static WorkItem InvokeDelegate(Delegate target, params object[] args)    
   
/// <summary>    
/// 执行委托操作    
/// </summary>    
/// <param name="target">目标委托对象</param>
public static WorkItem InvokeDelegate(Delegate target)    
   
/// <summary>    
/// 中止指定的队列中委托    
/// </summary>    
/// <param name="target">目标委托对象</param>    
/// <returns>项目队列中止操作的状态</returns>
public static WorkItemStatus AbortDelegate(WorkItem target)  

2)辅助类DelegateHelper的使用例子代码如下所示

private void btnDelegeteHelper_Click(object sender, EventArgs e)    
{    
    //无参数的委托    
    DelegateHelper.InvokeDelegate(new UpdateTextDelegate(this.UpdateText));     
   
    //有参数的委托    
    DelegateHelper.InvokeDelegate(new UpdateTextDelegate2(this.UpdateText), 100);    
   
}    
private delegate void UpdateTextDelegate();    
private delegate void UpdateTextDelegate2(int count);    
private void UpdateText()    
{    
    for (int i = 0; i < 1000; i++)    
    {    
        Thread.Sleep(100);    
    }    
}    
private void UpdateText(int count)    
{    
    for (int i = 0; i < count; i++)    
    {    
        Thread.Sleep(100);    
    }    
}  

7、线程池辅助操作类 ThreadPoolHelper。

实现效果

  1. 本辅助类主要是用来方便实现线程池辅助操作。。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>    
/// 方法委托    
/// </summary>
public delegate void WaitCallbackNew();    
   
/// <summary>    
/// 把执行方法放到队列中。    
/// 当线程池线程变为可用的时候,方法执行。    
/// </summary>    
/// <param name="callback">委托对象</param>
public static bool QueueUserWorkItem(WaitCallbackNew callback)    
   
/// <summary>    
/// 把执行方法放到队列中。    
/// 当线程池线程变为可用的时候,方法执行。    
/// </summary>    
/// <param name="proc">委托对象数组</param>    
/// <returns></returns>
public static bool QueueUserWorkItems(params WaitCallbackNew[] proc)    
   
/// <summary>    
///等待指定数组中所有元素收到信号    
/// </summary>
public static bool WaitAll()    
   
/// <summary>    
///等待指定数组中任何一个元素收到信号    
/// </summary>    
/// <returns>满足等待的对象数组索引</returns>
public static int WaitAny()  

2)辅助类ThreadPoolHelper的使用例子代码如下所示

private void UpdateText()    
{    
    for (int i = 0; i < 50; i++)    
    {    
        Thread.Sleep(100);    
    }    
}    
   
private void btnThreadPool_Click(object sender, EventArgs e)    
{    
    ThreadPoolHelper.QueueUserWorkItem(new ThreadPoolHelper.WaitCallbackNew(UpdateText));    
    ThreadPoolHelper.WaitAny();   //阻塞主界面线程,到5秒循环结束后,主界面可以操作 
}  

8、线程操作辅助类ThreadHelper。

实现效果

  1. 本辅助类主要是用来方便实现线程的各种操作,包括设置线程名称、优先级等及把执行方法放到队列中执行等基础性的线程操作。

实现代码

1)辅助类提供的方法接口如下所示:

/// <summary>    
/// 线程名称,最长不超过10个字符!    
/// </summary>    
/// <param name="name">线程名称</param>
public static void SetThreadName(string name)    
   
/// <summary>    
/// 设置线程优先级    
/// </summary>    
/// <param name="priority">线程优先级</param>
public static void SetThreadPriority(ThreadPriority priority)    
   
/// <summary>    
/// 设置主线程的UI Culture    
/// </summary>    
/// <param name="cultureName"></param>
public static void SetMainThreadUICulture(string cultureName)    
   
/// <summary>    
/// 把执行方法放到队列中,并指定了一个对象,它包含使用该方法的数据。    
/// 当线程池线程变为可用的时候,方法执行。    
/// </summary>    
/// <param name="callBack">工作项(WaitCallback)对象</param>    
/// <param name="threadName">线程名称,最长不超过10个字符!</param>    
/// <param name="priority">线程优先级</param>
public static bool Queue(WaitCallback callBack, string threadName, ThreadPriority priority)    
   
/// <summary>    
/// 把执行方法放到队列中,并指定了一个对象,它包含使用该方法的数据。    
/// 当线程池线程变为可用的时候,方法执行。    
/// </summary>    
/// <param name="callBack">工作项(WaitCallback)对象</param>    
/// <param name="threadName">线程名称,最长不超过10个字符!</param>    
/// <param name="state">执行方法的数据</param>    
/// <param name="priority">线程优先级</param>
public static bool Queue(WaitCallback callBack, string threadName, object state, ThreadPriority priority)    
   
/// <summary>    
/// 线程休眠一段毫秒时间    
/// </summary>    
/// <param name="millisecondsTimeout">一段毫秒时间</param>
public static void Sleep(int millisecondsTimeout)    
   
/// <summary>    
/// 线程休眠一段时间    
/// </summary>    
/// <param name="timeOut"></param>
public static void Sleep(TimeSpan timeOut)   

2)辅助类ThreadHelper的使用例子代码如下所示

CHM帮助文档持续更新中,统一下载地址是: http://www.iqidi.com/download/commonshelp.rar

公用类库DLL+XML注释文件下载地址是:http://files.cnblogs.com/wuhuacong/WHC.OrderWater.Commons.rar

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,646评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,979评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,391评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,356评论 0 215
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,740评论 3 293
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,836评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,022评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,764评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,487评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,728评论 2 252
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,200评论 1 263
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,548评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,217评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,134评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,921评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,919评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,766评论 2 274

推荐阅读更多精彩内容