java线程池源码解析

先上一张类图。jdk版本1.8.0_152


java线程池类图 (1).png

Executor

最基础的接口类,只有一个执行方法定义。
void execute(Runnable command);
该接口的定位是一个可以提交任务的对象。
An object that executes submitted {@link Runnable} tasks. This interface provides a way of decoupling task submission from the mechanics of how each task will be run, including details of thread use, scheduling, etc. An {@code Executor} is normally used instead of explicitly creating threads. For example, rather than invoking {@code new Thread(new(RunnableTask())).start()} for each of a set of tasks.
一个可以用来提交Runnable任务的对象。该接口可以解耦任务运行的机制。包括执行细节、线程使用、调度等。一个Executor实例通常用避免显式地创建线程。比如,避免直接新建Thread实例来运行每个任务。

ExecutorService

继承自Executor。
An {@link Executor} that provides methods to manage termination and methods that can produce a {@link Future} for tracking progress of one or more asynchronous tasks.
用来提供方法,管理、终止和追踪异步任务的进度。

void shutdown();
Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. Invocation has no additional effect if already shut down.
This method does not wait for previously submitted tasks to complete execution. Use {@link #awaitTermination awaitTermination}to do that.
初始化一个有序的关闭,已提交的任务会被执行完成,新任务会被拒绝。如果线程池已经是关闭状态,不会执行动作。
这个不会等待之前已经提交的任务,awaitTermination方法会等待。

boolean awaitTermination();
Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
阻塞一直到所有任务完成,或者达到超时时间,或者当前线程被中断。

Future<?> submit();
Submits a value-returning task for execution and returns a Future representing the pending results of the task. The Future's {@code get} method will return the task's result upon successful completion.
提交一个有返回值的任务去执行。返回一个Future对象。如果任务执行成功,Future对象会返回任务执行结果。

List<Future<T>> invokeAll();
Executes the given tasks, returning a list of Futures holding their status and results when all complete. {@link Future#isDone} is {@code true} for each element of the returned list. Note that a <em>completed</em> task could have terminated either normally or by throwing an exception. The results of this method are undefined if the given collection is modified while this operation is in progress.
执行入参里面的所有任务,当全部执行完成,返回Future列表,里面包含任务执行状态和结果。
如果执行过程中,入参被修改,方法返回结果会是未定义(?)

T invokeAny();
Executes the given tasks, returning the result of one that has completed successfully (i.e., without throwing an exception), if any do. Upon normal or exceptional return, tasks that have not completed are cancelled. The results of this method are undefined if the given collection is modified while this operation is in progress.
执行入参的任务,如果有至少一个任务执行成功,返回那个任务的结果。如果入参集合在执行过程中被修改,方法返回结果会是未定义(?)

AbstractExecutorService

继承自ExecutorService。
Provides default implementations of {@link ExecutorService} execution methods. This class implements the {@code submit}, {@code invokeAny} and {@code invokeAll} methods using a {@link RunnableFuture} returned by {@code newTaskFor}, which defaults to the {@link FutureTask} class provided in this package. For example, the implementation of {@code submit(Runnable)} creates an associated {@code RunnableFuture} that is executed and returned. Subclasses may override the {@code newTaskFor} methods to return {@code RunnableFuture} implementations other than {@code FutureTask}.
提供了执行方法的默认实现。该类实现了submit、invokeAny、invokeAll方法,使用newTaskFor方法来返回一个RunnableFuture对象(继承了Runnable和Future),FutureTask是RunnableFuture的一个实现。例如,submit的实现,创建了一个可以被执行和返回的RunnableFuture。该类的子类可以覆盖newTaskFor方法,来返回除FutureTask之外的RunnableFuture实现。

RunnableFuture<T> newTaskFor()
返回了一个FutureTask对象。

ScheduledExecutorService

继承自ExecutorService。
An {@link ExecutorService} that can schedule commands to run after a given delay, or to execute periodically.
可以让命令在指定延迟后执行,或者周期执行。

<V> ScheduledFuture<V> schedule();
Creates and executes a one-shot action that becomes enabled after the given delay.
指定延迟后,传入的任务变为可执行。

ScheduledFuture<?> scheduleAtFixedRate();
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after {@code initialDelay} then {@code initialDelay+period}, then {@code initialDelay + 2 * period}, and so on.
If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor. If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
创建和执行一个周期动作,这个动作在initial delay之后被激活,接下来每个周期被激活。意思是说,initialDelay、initialDelay+period、initialDelay + 2 * period等等时间点,可以执行任务。
如果任意一次任务执行抛出异常,后续的执行会被禁止。否则,这个任务只能通过取消和终止来终结。如果任务的任何一次执行时间超过了周期,那么接下来的执行会延迟启动,不会按照周期执行。

ScheduledFuture<?> scheduleWithFixedDelay();
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next. If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor.
创建和执行一个周期动作,这个动作在initial delay之后被激活,然后在一次执行终止和下一次执行开始之前再次被激活。如果有一次任务的执行抛出异常,接下来的执行被禁止。否则,任务只有在取消和执行器终结时才会终止。
和scheduleAtFixedRate不同的是,scheduleAtFixedRate是固定周期,scheduleWithFixedDelay是在上一次执行之后的一个延迟之后被激活。

ThreadPoolExecutor

An {@link ExecutorService} that executes each submitted task using one of possibly several pooled threads, normally configured using {@link Executors} factory methods.
继承自AbstractExecutorService。使用一个或多个池内的线程来执行提交的任务。通常情况下会使用Executors作为工厂方法。

Thread pools address two different problems: they usually provide improved performance when executing large numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and managing the resources, including threads, consumed when executing a collection of tasks. Each {@code ThreadPoolExecutor} also maintains some basic statistics, such as the number of completed tasks.
线程池旨在解决两个问题:

  1. 因为减少每个任务的调用,当执行大量异步任务时,线程池有性能提升。
  2. 线程池可以定义资源界限、管理资源,包括线程,线程会在执行任务时被使用。每个线程池同时维护一些统计数据,比如完成的任务数量。

To be useful across a wide range of contexts, this class provides many adjustable parameters and extensibility hooks. However, programmers are urged to use the more convenient {@link Executors} factory methods {@link Executors#newCachedThreadPool} (unbounded thread pool, with automatic thread reclamation), {@link Executors#newFixedThreadPool} (fixed size thread pool) and {@link Executors#newSingleThreadExecutor} (single background thread), that preconfigure settings for the most common usage scenarios. Otherwise, use the following guide when manually configuring and tuning this class:
为了在大范围上下文中都保持有用,这个类提供了很多可调参数和可扩展的钩子。然而,开发者迫切需要更方面的工厂方法,比如Executors#newCachedThreadPool(无边界线程池,线程自动回收),Executors#newFixedThreadPool(固定大小线程池)和Executors#newSingleThreadExecutor(单线程池),这些预配置的实例可以满足大多数使用场景。
接下来是用户使用手册。

Core and maximum pool sizes(核心线程数和最大线程数)

A {@code ThreadPoolExecutor} will automatically adjust the pool size (see {@link #getPoolSize}) according to the bounds set by corePoolSize (see {@link #getCorePoolSize}) and maximumPoolSize (see {@link #getMaximumPoolSize}).
ThreadPoolExecutor实例会根据核心线程数和最大线程数的边界,自动调成池大小。

When a new task is submitted in method {@link #execute(Runnable)}, and fewer than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads are idle. If there are more than corePoolSize but less than maximumPoolSize threads running, a new thread will be created only if the queue is full. By setting corePoolSize and maximumPoolSize the same, you create a fixed-size thread pool. By setting maximumPoolSize to an essentially unbounded value such as {@code Integer.MAX_VALUE}, you allow the pool to accommodate an arbitrary number of concurrent tasks. Most typically, core and maximum pool sizes are set only upon construction, but they may also be changed dynamically using {@link #setCorePoolSize} and {@link #setMaximumPoolSize}. </dd>
当新的任务通过exexute方法提交时,当前线程池内线程数小于核心线程数,会创建一个新的线程来处理请求,即使其他的工作线程是空闲状态。如果线程池内线程数大于等于核心线程数小于最大线程数,只有当队列满的时候才会创建新的线程。通过设置核心线程数和最大线程数一致,就创建了一个固定大小的线程池。设置最大线程数是一个本质上无界值,比如Integer.MAX_VALUE,那么线程池可以容纳任意数量的并行任务。最典型的场景,核心线程数和最大线程数只有在构建的时候被设置,但是,也可以动态修改。

On-demand construction(按需构造)

By default, even core threads are initially created and started only when new tasks arrive, but this can be overridden dynamically using method {@link #prestartCoreThread} or {@link #prestartAllCoreThreads}. You probably want to prestart threads if you construct the pool with a non-empty queue.
默认情况,即使是核心线程内,也是在新任务到达时被创建和初始化。但是,这个可以通过使用prestartCoreThread或者prestartAllCoreThreads来动态修改。如果创建线程池的时候,队列就是非空的,就需要预启动线程。

Creating new threads(创建新线程)

New threads are created using a {@link ThreadFactory}. If not otherwise specified, a {@link Executors#defaultThreadFactory} is used, that creates threads to all be in the same {@link ThreadGroup} and with the same {@code NORM_PRIORITY} priority and non-daemon status. By supplying a different ThreadFactory, you can alter the thread's name, thread group, priority, daemon status, etc. If a {@code ThreadFactory} fails to create a thread when asked by returning null from {@code newThread}, the executor will continue, but might not be able to execute any tasks. Threads should possess the "modifyThread" {@code RuntimePermission}. If worker threads or other threads using the pool do not possess this permission, service may be degraded: configuration changes may not take effect in a timely manner, and a shutdown pool may remain in a state in which termination is possible but not completed.
新线程是使用ThreadFactory来创建的。如果不是特殊情况,会使用Executors#defaultThreadFactory,该工厂创建的线程都是同一个ThreadGroup,同一个优先级,非daemon状态。通过提供不同的ThreadFactory,你可以修改线程名称、线程组、优先级、daemon状态等。如果一个ThreadFactory创建线程失败,执行器会继续(?),但是不能执行任何任务。线程应该持有"modifyThread"的RuntimePermission(修改线程权限)。如果工作线程或者其他线程使用线程池,但是没有持有权限,服务会被降级:配置变化不会生效,关闭的线程池会保持在一个即将终结但是没有完成的状态。

Keep-alive times(保活时间)

If the pool currently has more than corePoolSize threads, excess threads will be terminated if they have been idle for more than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}). This provides a means of reducing resource consumption when the pool is not being actively used. If the pool becomes more active later, new threads will be constructed. This parameter can also be changed dynamically using method {@link #setKeepAliveTime(long, TimeUnit)}. Using a value of {@code Long.MAX_VALUE} {@link TimeUnit#NANOSECONDS} effectively disables idle threads from ever terminating prior to shut down. By default, the keep-alive policy applies only when there are more than corePoolSize threads. But method {@link #allowCoreThreadTimeOut(boolean)} can be used to apply this time-out policy to core threads as well, so long as the keepAliveTime value is non-zero.
如果线程池当前线程数超过corePoolSize,多余的线程会在空闲超过keepAliveTime之后被终止。当线程池没有被使用时,这种方式可以减少资源消耗。如果线程池再次活跃,新线程会创建。这个方法可以使用setKeepAliveTime来修改。使用Long.MAX_VALUE可以禁止空闲线程关闭。通常,保活策略仅在当前有超过corePoolSize的线程时会生效。但是allowCoreThreadTimeOut可以允许该策略对核心线程生效(同时keepAliveTime为非0)。

Queuing(队列)

Any {@link BlockingQueue} may be used to transfer and hold submitted tasks. The use of this queue interacts with pool sizing:
任意的BlockingQueue实现都可以用来传输和持有任务。队列的使用和线程池大小相关影响。

If fewer than corePoolSize threads are running, the Executor always prefers adding a new thread rather than queuing.
如果执行线程数小于corePoolSize,执行器会增加新线程而不是入队列。

If corePoolSize or more threads are running, the Executor always prefers queuing a request rather than adding a new thread.
如果大于等于corePoolSize的线程数在运行,执行器会入队请求,不会增加线程。

If a request cannot be queued, a new thread is created unless this would exceed maximumPoolSize, in which case, the task will be rejected.
如果请求没有入队列,新线程会创建,除非当前执行线程数已经超过maximumPoolSize。该情况下,任务会被拒绝。

几种排队策略:

Direct handoffs.(直接传递)

A good default choice for a work queue is a {@link SynchronousQueue} that hands off tasks to threads without otherwise holding them. Here, an attempt to queue a task will fail if no threads are immediately available to run it, so a new thread will be constructed. This policy avoids lockups when handling sets of requests that might have internal dependencies. Direct handoffs generally require unbounded maximumPoolSizes to avoid rejection of new submitted tasks. This in turn admits the possibility of unbounded thread growth when commands continue to arrive on average faster than they can be processed.

一个不错的默认选择是使用同步队列( SynchronousQueue), 将任务直接交给线程处理而不是存储起来. 如果没有线程及时处理,任务也不能被成功存储,所以新的线程会被创建。当处理有内部依赖的请求时,这个策略避免了锁。直接传递需要无边界的maximumPoolSize,来避免新提交任务被拒绝。当命令到达速度大于消费速度时,这个反而造成了无界线程增长的可能。

Unbounded queues.(无界队列)

Using an unbounded queue (for example a {@link LinkedBlockingQueue} without a predefined capacity) will cause new tasks to wait in the queue when all corePoolSize threads are busy. Thus, no more than corePoolSize threads will ever be created. (And the value of the maximumPoolSize therefore doesn't have any effect.) This may be appropriate when each task is completely independent of others, so tasks cannot affect each others execution; for example, in a web page server. While this style of queuing can be useful in smoothing out transient bursts of requests, it admits the possibility of unbounded work queue growth when commands continue to arrive on average faster than they can be processed.
使用无界队列(比如LinkedBlockingQueue)会使新任务进入队列等待,当前核心线程都在执行时。因此,corePoolSize之外的线程不会创建。maximumPoolSize不会生效。当任务之间没有依赖时,该策略是合适的,因此任务不会影响其他任务执行。比如,一个网页服务器。在平滑伴有短暂爆发流量的场景下,该排队方式是有用的。当命令生产速度大于小费速度时,它允许无边界工作队列增长。

Bounded queues.(有界队列)

A bounded queue (for example, an {@link ArrayBlockingQueue}) helps prevent resource exhaustion when used with finite maximumPoolSizes, but can be more difficult to tune and control. Queue sizes and maximum pool sizes may be traded off for each other: Using large queues and small pools minimizes CPU usage, OS resources, and context-switching overhead, but can lead to artificially low throughput. If tasks frequently block (for example if they are I/O bound), a system may be able to schedule time for more threads than you otherwise allow. Use of small queues generally requires larger pool sizes, which keeps CPUs busier but may encounter unacceptable scheduling overhead, which also decreases throughput.
当maximumPoolSize无限大时,有界队列可以防止资源耗耗尽,但是更难调整和控制。队列大小和线程池最大线程数需要互相权衡。使用大队列和小线程池,CPU使用、OS
资源利用率低和上下文切换频繁,但是会造成低吞吐量。如果任务频繁block,系统会为更多线程排期。使用小队列和大线程池,CPU利用率高但是会造成不可接受的调用开销,会降低吞吐量。

Rejected tasks(拒绝任务)

New tasks submitted in method {@link #execute(Runnable)} will be <em>rejected</em> when the Executor has been shut down, and also when the Executor uses finite bounds for both maximum threads and work queue capacity, and is saturated. In either case, the {@code execute} method invokes the {@link RejectedExecutionHandler#rejectedExecution(Runnable, ThreadPoolExecutor)} method of its {@link RejectedExecutionHandler}. Four predefined handler policies are provided:
当执行器被关闭或者队列线程池都满时,新任务会被拒绝。在上述场景中,execute方法会调用RejectedExecutionHandler#rejectedExecution方法。有四种定义好的拒绝策略。

ThreadPoolExecutor.AbortPolicy
抛出RejectedExecutionException异常。
ThreadPoolExecutor.CallerRunsPolicy
使用调用者线程执行任务,会降低新任务的消费速度。
ThreadPoolExecutor.DiscardPolicy
丢弃任务。
ThreadPoolExecutor.DiscardOldestPolicy
丢弃最老的任务,并且重试执行任务。

此外,还可以自定义拒绝策略,需要实现RejectedExecutionHandler接口。

Hook methods(钩子方法)

This class provides {@code protected} overridable {@link #beforeExecute(Thread, Runnable)} and {@link #afterExecute(Runnable, Throwable)} methods that are called before and after execution of each task. These can be used to manipulate the execution environment; for example, reinitializing ThreadLocals, gathering statistics, or adding log entries. Additionally, method {@link #terminated} can be overridden to perform any special processing that needs to be done once the Executor has fully terminated.
该类提供了可覆盖的beforeExecute、afterExecute方法,用来在任务执行前后调用。这些方法可以用来操作执行环境。比如,重新初始化ThreadLocal变量、手机数据、增加日志。另外,可以覆盖terminated方法的实现,在执行器完全终止时处理某些行为。

If hook or callback methods throw exceptions, internal worker threads may in turn fail and abruptly terminate.
如果钩子或者回调方法抛出异常,内部工作线程可能会失败并且终止。

Queue maintenance(队列维护)

Method {@link #getQueue()} allows access to the work queue for purposes of monitoring and debugging. Use of this method for any other purpose is strongly discouraged. Two supplied methods, {@link #remove(Runnable)} and {@link #purge} are available to assist in storage reclamation when large numbers of queued tasks become cancelled.
getQueue方法允许访问工作队列,出于监控或者调试的目的。如果是其他原因使用该方法,是强烈不建议的。两个已有方法,当大量入队任务被取消时,remove和purge(清除)可以用来回收存储。

Finalization(终结)

A pool that is no longer referenced in a program <em>AND</em> has no remaining threads will be {@code shutdown} automatically. If you would like to ensure that unreferenced pools are reclaimed even if users forget to call {@link #shutdown}, then you must arrange that unused threads eventually die, by setting appropriate keep-alive times, using a lower bound of zero core threads and/or setting {@link #allowCoreThreadTimeOut(boolean)}.
一个线程池不在被引用,挥着没有存活线程时将被自动关闭。如果你想要保证不被引用的线程池在用户忘记显式调用shutdown接口的情况下被回收,你需要通过设置保活时间,使用更小边界的队列,设置核心线程可回收,使闲置线程最终消亡。

构造函数

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
公有7个参数。
corePoolSize 核心线程数
maximumPoolSize 最大线程数
keepAliveTime 保活时间,空闲超过该时间并且超过核心线程数的线程会被回收。
unit 保活时间的时间单元
workQueue 任务队列,只会持有execute提交的任务。
threadFactory 用来创建线程的工厂实例
handler 拒绝策略处理器

Executors

工具类和工厂方法类,包含以下几种方法。

  1. 创建和返回ExecutorService实例。
  2. 创建和返回ScheduledExecutorService实例。
  3. 创建和返回"wrapped"后的ExecutorService实例,禁止重配置。
  4. 创建和返回ThreadFactory。
  5. 创建和返回Callable实例,用来在调用execute方法时使用。

ExecutorService newFixedThreadPool(int nThreads)
Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue. At any point, at most {@code nThreads} threads will be active processing tasks. If additional tasks are submitted when all threads are active, they will wait in the queue until a thread is available. If any thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks. The threads in the pool will exist until it is explicitly {@link ExecutorService#shutdown shutdown}.
创建一个线程池,可以重用固定数量的线程,使用一个共享的无界队列。在任何时候,最多nThreads(入参)个线程可以处理任务。在所有线程都运行时,有新的任务提交的话,新任务会进入队列知道有线程空闲。如果有线程因为执行失败而销毁,同时还有任务需要执行,新线程会创建。池内线程会存在一直到线程池显示关闭。

ExecutorService newWorkStealingPool(int parallelism)
Creates a thread pool that maintains enough threads to support the given parallelism level, and may use multiple queues to reduce contention. The parallelism level corresponds to the maximum number of threads actively engaged in, or available to engage in, task processing. The actual number of threads may grow and shrink dynamically. A work-stealing pool makes no guarantees about the order in which submitted tasks are executed.
创建一个线程池,持有足够的线程数,来支持给定的并发级别,并且可以使用多个队列来减少竞争。并发级别相当于活跃的最大线程数,或者待执行状态线程。真实的线程数量可以动态增减。一个工作窃取池不保证提交任务的执行顺序。

ExecutorService newSingleThreadExecutor()
Creates an Executor that uses a single worker thread operating off an unbounded queue. (Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.) Tasks are guaranteed to execute sequentially, and no more than one task will be active at any given time. Unlike the otherwise equivalent {@code newFixedThreadPool(1)} the returned executor is guaranteed not to be reconfigurable to use additional threads.
创建一个执行器,只有一个工作线程,操作一个无界队列。无论何时这个线程被关闭,同时有新任务需要执行,都会有新线程被创建。任务被保证顺序执行,任何时候都只有一个线程被执行。不向newFixedThreadPool(1)等等价实现,该实现保证不可以修改配置,不能增加线程数。

ExecutorService newCachedThreadPool()
Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. These pools will typically improve the performance of programs that execute many short-lived asynchronous tasks. Calls to {@code execute} will reuse previously constructed threads if available. If no existing thread is available, a new thread will be created and added to the pool. Threads that have not been used for sixty seconds are terminated and removed from the cache. Thus, a pool that remains idle for long enough will not consume any resources. Note that pools with similar properties but different details (for example, timeout parameters) may be created using {@link ThreadPoolExecutor} constructors.
创建一个线程池,按需创建新线程,如果有线程空闲会重用。该实现在执行较多短周期异步任务的场景下,会显著提交性能。调用execute方法会优先复用已创建的线程。如果没有线程可用,会创建新线程。线程超过60s没使用会被终止并删除。因此,该线程池如果长时间空闲不会消耗资源。拥有类似配置的newCachedThreadPool实现,可以使用ThreadPoolExecutor构造器来创建。

ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
Creates a thread pool that can schedule commands to run after a given delay, or to execute periodically.
创建一个可以周期管理命令的线程池,可以指定延迟执行,或者周期执行。

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

推荐阅读更多精彩内容