Core Java

Core Java

  • suppose every javaer need to know

Collection

I/O

File & Directory

  • java.io.File
File file1 = new File("D:\\Document\\books\\java.pdf");
File file2 = new File("/opt/data/my.txt");
File file3 = new File("/opt/data", "my.txt");
  • Paths of File
File file = new File("./pom.xml");
System.out.println("Absolute path = " + file.getAbsolutePath());
System.out.println("Canonical path = " + file.getCanonicalPath());
System.out.println("Name = " + file.getName());
System.out.println("Parent = " + file.getParent());
System.out.println("Path = " + file.getPath());
System.out.println("Is absolute = " + file.isAbsolute());

Output:

Absolute path = /Users/lenicliu/git/eg-java/eg-java-io/./pom.xml
Canonical path = /Users/lenicliu/git/eg-java/eg-java-io/pom.xml
Name = pom.xml
Parent = .
Path = ./pom.xml
Is absolute = false

  • List Directories
File dir = new File(".");
File[] folders = dir.listFiles((f) -> f.isDirectory()); // java.io.FileFilter
for (File folder : folders) {
    System.out.println(folder);
}

Output:

./.settings
./src
./target

RandomAccessFile

  • Read & Write
RandomAccessFile file = new RandomAccessFile("user.dat", "rw");

file.writeUTF("username:lenicliu\n");
file.writeUTF("birthday:1987-09\n");

file.close();

// comment -> java.io.IOException: Stream Closed
file = new RandomAccessFile("user.dat", "r");

System.out.println(file.readLine());
System.out.println(file.readLine());

file.close();

InputStream & OutputStream

  • InputStream & OutputStream is used to handle bytes
InputStream input = new ByteArrayInputStream(new byte[] { (byte) 4 });
int read = -1;
while ((read = input.read()) != -1) {
    System.out.println(read); // output : 4
}
input.close();

OutputStream output = new ByteArrayOutputStream();
output.write(new byte[] { (byte) 2, (byte) 39 });
output.close();
  • Read File & Write File
FileOutputStream output = new FileOutputStream("user.dat");
output.write("lenicliu, male".getBytes());
output.close();

FileInputStream input = new FileInputStream("user.dat");
byte[] buffer = new byte[input.available()];
input.read(buffer);
input.close();
System.out.println(new String(buffer));// Output : lenicliu, male
  • IOException
    • This is an example of OutputStream, InputStream is similar to it
FileOutputStream output = null;
try {
    output = new FileOutputStream("user.dat");
} catch (FileNotFoundException e) {
    e.printStackTrace();
}
try {
    output.write("lenicliu, male".getBytes());
} catch (IOException e) {
    e.printStackTrace();
} finally {
    // make sure stream closed
    try {
        if (output != null) {
            output.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
  • try-with-resources
try (FileInputStream input = new FileInputStream("user.dat")) {
    byte[] buffer = new byte[input.available()];
    input.read(buffer);
    // input.close(); // it's unnecessary
    System.out.println(new String(buffer));
} catch (IOException e) {
    e.printStackTrace();
}
  • Object Serialization and Deserialization
// 1) class User { // throw java.io.NotSerializableException
class User implements Serializable {
    String              name;
    transient String    sex; // 3) it will be lost
    
    // 2) throw java.io.InvalidClassException if different value read
    private static final long   serialVersionUID    = 2933636808737636316L;

    public User(String name, String sex) {
        super();
        this.name = name;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public String getSex() {
        return sex;
    }
}

ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("user.dat"));
output.writeObject(new User("lenicliu", "male"));
output.close();

ObjectInputStream input = new ObjectInputStream(new FileInputStream("user.dat"));
User user = (User) input.readObject();
input.close();
System.out.println("name is " + user.getName());
System.out.println("sex is " + user.getSex());// 3) output : sex is null

Reader & Writer

  • Reader & Writer are used to handle chars
    • FileReader & FileWriter
    • InputStreamReader & OutputStreamWriter
    • BufferedReader & BufferedWriter
      • BufferedReader.readLine()
  • FileReader & FileWriter
FileWriter writer = new FileWriter("user.dat");
writer.write("lenicliu, male");
writer.close();

FileReader reader = new FileReader("user.dat");
int read = -1;
while ((read = reader.read()) != -1) {
    System.out.print((char) read);
}
System.out.println();
reader.close();

Note: Don't forget to handle IOException

Performance

  • Create a big file by following command:
    • mac : mkfile -n 1g gigabyte.dat
    • linux : dd if=/dev/zero of=gigabyte.dat bs=1M count=1024
    • win : fsutil file createnew gigabyte.dat 1073741824
  • Let's do a simple experiment: Read a big file, 1G
private static void useFileReader(File dat, int size) throws FileNotFoundException, IOException {
    long begin = System.currentTimeMillis();
    FileReader reader = new FileReader(dat);
    char[] buffer = new char[size];
    while (reader.read(buffer) != -1) {
    }
    reader.close();
    long end = System.currentTimeMillis();
    System.out.println("FileReader : buffer size = " + size + "," + (end - begin) / 1000.0 + " seconds.");
}

private static void useFileInputStream(File dat, int size) throws FileNotFoundException, IOException {
    long begin = System.currentTimeMillis();
    FileInputStream input = new FileInputStream(dat);
    byte[] buffer = new byte[size];
    while (input.read(buffer) != -1) {
    }
    input.close();
    long end = System.currentTimeMillis();
    System.out.println("FileInputStream : buffer size = " + size + "," + (end - begin) / 1000.0 + " seconds.");
}

public static void main(String[] args) throws IOException, ClassNotFoundException {
    File dat = new File("gigabyte.dat");
    useFileReader(dat, 512);
    useFileReader(dat, 1024);
    useFileReader(dat, 2048);
    useFileReader(dat, 4096);
    useFileReader(dat, 8192);

    useFileInputStream(dat, 512);
    useFileInputStream(dat, 1024);
    useFileInputStream(dat, 2048);
    useFileInputStream(dat, 4096);
    useFileInputStream(dat, 8192);
}

Output:

FileReader :    buffer size = 512,  1.08 seconds.
FileReader :    buffer size = 1024, 0.937 seconds.
FileReader :    buffer size = 2048, 0.895 seconds.
FileReader :    buffer size = 4096, 0.893 seconds.
FileReader :    buffer size = 8192, 0.884 seconds.
FileInputStream :   buffer size = 512,  1.756 seconds.
FileInputStream :   buffer size = 1024, 0.987 seconds.
FileInputStream :   buffer size = 2048, 0.592 seconds.
FileInputStream :   buffer size = 4096, 0.373 seconds.
FileInputStream :   buffer size = 8192, 0.29 seconds.

Socket

final int port = 10000;
final String EOF = "\n";

// server thread
new Thread(() -> {
    try {
        ServerSocket server = new ServerSocket(port);
        Socket socket = server.accept();
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String name = reader.readLine();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        writer.write("Hi, " + name + EOF);
        writer.flush();
        socket.close();
        server.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}).start();

// client thread
new Thread(() -> {
    try {
        Socket socket = new Socket("localhost", port);
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        writer.write("lenicliu" + EOF);
        writer.flush();
        System.out.println(reader.readLine()); // output : Hi, lenicliu
        socket.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}).start();

NIO

Buffers

Channels

  • FileChannel
File src = new File("/path/of/srcFile");
File dest = new File("/path/of/destFile");

FileInputStream in = null;
FileOutputStream ot = null;

try {
  in = new FileInputStream(src);
  ot = new FileOutputStream(dest);

  FileChannel ic = in.getChannel();
  FileChannel oc = ot.getChannel();

  ByteBuffer buffer = ByteBuffer.allocate(1024 * 8);
  buffer.clear();

  while (ic.read(buffer) != -1) {
    buffer.flip(); // flip before write
    oc.write(buffer);
    buffer.clear(); // make buffer empty for reading
  }
} catch (IOException e) {
  // handle exception
} finally {
  if (in != null) {
    try {
      in.close();
    } catch (IOException ignore) {
    }
  }
  if (ot != null) {
    try {
      ot.close();
    } catch (IOException ignore) {
    }
  }
}
  • ServerSocketChannel & SocketChannel
final InetSocketAddress localhost = new InetSocketAddress("127.0.0.1", 10000);

new Thread(() -> {
  try {
    ServerSocketChannel server = ServerSocketChannel.open();
    server.bind(localhost);
    SocketChannel socket = server.accept();
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    socket.read(buffer);
    buffer.flip();
    String name = new String(buffer.array());
    System.out.println("server recieved: " + name);
    socket.write(ByteBuffer.wrap(("Hi, " + name).getBytes()));
    socket.close();
    server.close();
  } catch (Exception e) {
    e.printStackTrace();
  }
}).start();

new Thread(() -> {
  try {
    SocketChannel socket = SocketChannel.open();
    socket.connect(localhost);
    socket.write(ByteBuffer.wrap("lenicliu".getBytes()));
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    socket.read(buffer);
    buffer.flip();
    System.out.println("client recieved: " + new String(buffer.array()));
    socket.close();
  } catch (Exception e) {
    e.printStackTrace();
  }
}).start();
  • DatagramChannel
final InetSocketAddress localhost = new InetSocketAddress("127.0.0.1", 10000);
new Thread(() -> {
  try {
    DatagramChannel server = DatagramChannel.open();
    server.bind(localhost);
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    SocketAddress address = server.receive(buffer);
    buffer.flip();
    String name = new String(buffer.array());
    System.out.println("server recieved: " + name);
    server.send(ByteBuffer.wrap(("Hi, " + name).getBytes()), address);
    server.close();
  } catch (Exception e) {
    e.printStackTrace();
  }
}).start();

new Thread(() -> {
  try {
    DatagramChannel client = DatagramChannel.open();
    client.send(ByteBuffer.wrap("lenicliu".getBytes()), localhost);
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    client.receive(buffer);
    buffer.flip();
    System.out.println("client recieved: " + new String(buffer.array()));
    client.close();
  } catch (Exception e) {
    e.printStackTrace();
  }
}).start();
  • Pipe
final Pipe pipe = Pipe.open();
new Thread(() -> {
  try {
    SinkChannel channel = pipe.sink();
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    buffer.put("Hi, lenicliu".getBytes());
    buffer.flip();// flip before write
    System.out.println("write: " + new String(buffer.array()));
    channel.write(buffer);
    channel.close();
  } catch (Exception e) {
    e.printStackTrace();
  }
}).start();

new Thread(() -> {
  try {
    SourceChannel channel = pipe.source();
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    channel.read(buffer);
    channel.close();
    buffer.flip();
    System.out.println("read: " + new String(buffer.array()));
  } catch (Exception e) {
    e.printStackTrace();
  }
}).start();

Selectors

Thread & Concurrency

Thread & Runnable

  • Thread is class, Runnable is interface
  • Thread State
    • NEW -> not started
    • RUNNABLE -> running/executing
    • BLOCKED -> blocked by synchronized, lock, etc...
    • WAITING
    • TIME_WAITING
    • TERMINATED -> exited
  • Daemon
  • More
    • Interrupting new Thread().interrupt()
    • Joining new Thread().join()
    • Sleeping Thread.sleep(1000)

Synchronization

  • synchronized method
class Counter{
    private int count = 0;
    public synchronized int get(){
        return count++;
    }   
}
  • synchronized block
class Counter{
    private int     count = 0;
    private Object  lock = new Object();
    public int get(){
        synchronized(lock){
            return count++;
        }
    }   
}
  • problem
    • Deadlock : T1 & T2 waits for the resource that's held by each other
    • Livelock : T1 keeps retrying operation that always fail, so can't make progress
    • Starvation : T1 always denied to access the resource, so can't make progress

Waiting & Notification

  • wait() cause the current thread to wait until another thread invokes the notify() or notifyAll()
  • notify() wake up any one of threads that are waiting on this object's monitor
  • both of wait() and notify() must be called from within a synchronized context
synchronized(obj){
    while(<condition>){
        obj.wait();
    }
}

Producer & Consumer

class SharedInt {
    int     value       = -1;
    boolean available   = false;
    
    synchronized int get() {
        while (!this.available) {
            try {
                this.wait();
            } catch (InterruptedException e) {}
        }
        this.available = false;
        this.notify();
        return this.value;
    }
    
    synchronized void set(int value) {
        while (this.available) {
            try {
                this.wait();
            } catch (InterruptedException e) {}
        }
        this.value = value;
        this.available = true;
        this.notify();
    }
}

SharedInt shared = new SharedInt();

Runnable producer = () -> {
    int[] values = IntStream.range(0, 10).toArray();
    for (int value : values) {
        synchronized (shared) {
            shared.set(value);
            System.out.println("producer : " + value);
        }
    }
};

Runnable consumer = () -> {
    while (true) {
        synchronized (shared) {
            int value = shared.get();
            System.out.println("consumer : " + value);
            if (value == 9) { break; }
        }
    }
};

new Thread(consumer).start();
new Thread(producer).start();

More

  • Thread Groups
  • Thread Local It's a separate storage slot to each thread
public class Main {
   private static ThreadLocal<String> messages = new ThreadLocal<>();
   public static void main(String[] args) {
      Runnable r = () -> {
        // every thread could hold diff value here
        messages.set(variable);
        String value = messages.get();
      };
      // ...
   }
}
  • Timer
    • Timer start a thread
      • TaskQueue is a priority queue of TimerTasks ordered by nextExecutiveTime
    • TimerTask implement Runnable

Executor

  • submit(Runnable) & submit(Callable)
  • awaitTermination(long, TimeUnit)
    • block until all tasks have finished after a shutdown() request.
    • timeout & interrupt
Executor executor = (runnable) -> new Thread(runnable).start();
executor.execute(() -> System.out.println("Hello Executor"));

ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.execute(() -> System.out.println("Hello ExecutorService"));
executorService.shutdown();

Synchronizers

  • Countdown Latches
CountDownLatch latch = new CountDownLatch(3);
Runnable r = () -> {
    latch.countDown();
};
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
latch.await();
  • Cyclic Barriers
Runnable finish = () -> {
    System.out.println("S:" + System.currentTimeMillis());
};
// need 3 task reached the barrier, and then 'finish' will execute
CyclicBarrier barrier = new CyclicBarrier(3, finish);
Runnable worker = () -> {
    try {
        TimeUnit.SECONDS.sleep(2);// do sth
        barrier.await();
    } catch (Exception ignore) {
    }
};
System.out.println("E:" + System.currentTimeMillis());
new Thread(worker).start();
new Thread(worker).start();
new Thread(worker).start();// commented -> endless

Output:

E:1461684706399
S:1461684708401
  • Exchangers
  • Semaphores
Semaphore semaphore = new Semaphore(3, true);
Runnable worker = () -> {
    try {
        semaphore.acquire();
        // do sth.
    } catch (InterruptedException ignore) {
    } finally {
        semaphore.release();
    }
};
new Thread(worker).start();
new Thread(worker).start();
new Thread(worker).start();
// This one will wait for calling semaphore.release()
new Thread(worker).start();
  • Phasers

Locking

  • Lock core interface, lock() & unlock()
  • ReentrantLock
ReentrantLock lock = new ReentrantLock();
Runnable worker = () -> {
    lock.lock();
    // lock.lock(); // uncomment -> endless
    try {
        TimeUnit.SECONDS.sleep(2);// do sth.
    } catch (InterruptedException e) {
    } finally {
        lock.unlock();
    }
};
  • Condition
class SharedInt {
    int         value       = -1;
    boolean     available   = false;
    Lock        lock        = new ReentrantLock();
    Condition   condition   = lock.newCondition();

    void lock() { lock.lock(); }

    void unlock() { lock.unlock(); }

    int get() {
        lock.lock();
        try {
            while (!this.available) {
                try { this.condition.await(); }
                catch (InterruptedException e) {}
            }
            this.available = false;
            this.condition.signal();
            return this.value;
        } finally {
            lock.unlock();
        }
    }

    void set(int value) {
        lock.lock();
        try {
            while (this.available) {
                try { this.condition.await(); }
                catch (InterruptedException e) {}
            }
            this.value = value;
            this.available = true;
            this.condition.signal();
        } finally {
            lock.unlock();
        }
    }
}

SharedInt shared = new SharedInt();

Runnable producer = () -> {
    int[] values = IntStream.range(0, 10).toArray();
    for (int value : values) {
        shared.lock();
        shared.set(value);
        System.out.println("producer : " + value);
        shared.unlock();
    }
};

Runnable consumer = () -> {
    int value = -1;
    while (value != 9) {
        shared.lock();
        value = shared.get();
        System.out.println("consumer : " + value);
        shared.unlock();
    }
};

new Thread(consumer).start();
new Thread(producer).start();
  • ReadWriteLock
  • ReentrantReadWriteLock
class ReadWriteLockList {
    List<String>    list    = new ArrayList<>();
    ReadWriteLock   lock    = new ReentrantReadWriteLock();
    Lock            rlock   = lock.readLock();
    Lock            wlock   = lock.writeLock();

    public String get(int index) {
        rlock.lock();
        try {
            return list.get(index);
        } finally {
            rlock.unlock();
        }
    }

    public String remove(int index) {
        wlock.lock();
        try {
            return list.remove(index);
        } finally {
            wlock.unlock();
        }
    }
    // ...
}

More

  • Concurrent Collections
    • java.util.concurrent.BlockingQueue<E>
      • java.util.concurrent.ArrayBlockingQueue<E>
      • java.util.concurrent.LinkedBlockingQueue<E>
      • java.util.concurrent.PriorityBlockingQueue<E>
      • java.util.concurrent.SynchronousQueue<E>
    • java.util.concurrent.ConcurrentMap<K, V>
      • java.util.concurrent.ConcurrentHashMap<K, V>
  • Atomic
class Counter{
    private AtomicInteger     count = new AtomicInteger(0);
    public int get(){
        return count.getAndIncrement();
    }   
}
  • Completion Services
class CalculatePI implements Callable<BigDecimal> {
    int n;

    public CalculatePI(int n) {
        this.n = n;
    }

    @Override
    public BigDecimal call() throws Exception {
        MathContext mc = new MathContext(100, RoundingMode.HALF_UP);
        // pi = 1/1 - 1/3 + 1/7 - 1/9 + 1/11 - 1/13 .....
        BigDecimal pi = BigDecimal.ZERO;
        for (int i = 1; i <= n; i++) {
            if (i % 2 == 1) {
                pi = pi.add(BigDecimal.ONE.divide(new BigDecimal(2 * i - 1), mc));
            } else {
                pi = pi.subtract(BigDecimal.ONE.divide(new BigDecimal(2 * i - 1), mc));
            }
        }
        return pi.multiply(new BigDecimal(4), mc);
    }
}

ExecutorService es = Executors.newFixedThreadPool(8);
CompletionService<BigDecimal> cs = new ExecutorCompletionService<BigDecimal>(es);
long begin = System.currentTimeMillis();
cs.submit(new CalculatePI(10000000));
System.out.println(cs.take().get());
long end = System.currentTimeMillis();
System.out.println("Time:" + (end - begin));
es.shutdown();

Output:

3.141592553589793238462893383279502881072169399375201133474944586897660156286702367768659759356643435
Time:3896
  • Fork & Join
class Factorial extends RecursiveTask<BigDecimal> {
    final long start, end, threshold = 10;

    public Factorial(long end) {
        this(1, end);
    }

    private Factorial(long start, long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected BigDecimal compute() {
        MathContext mc = new MathContext(100, RoundingMode.HALF_UP);
        BigDecimal factorial = BigDecimal.ONE;
        if (end - start < threshold) {
            for (long i = start; i <= end; i++) {
                factorial = factorial.multiply(new BigDecimal(i), mc);
            }
        } else {
            long middle = (start + end) / 2;
            Factorial left = new Factorial(start, middle);
            Factorial right = new Factorial(middle + 1, end);
            left.fork();
            right.fork();
            factorial = left.join().multiply(right.join());
        }
        return factorial;
    }
}
ForkJoinPool forkJoinPool = new ForkJoinPool();
System.out.println(forkJoinPool.submit(new Factorial(100)).get());
  • Use ForkJoinPool & RecursiveTask to enhance performance : PI Calculation
final MathContext mc = new MathContext(100, RoundingMode.HALF_UP);
class Pi extends RecursiveTask<BigDecimal> {
    final long start, end, threshold = 10000;

    public Pi(long end) {
        this(1, end);
    }

    private Pi(long start, long end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected BigDecimal compute() {
        BigDecimal pi = BigDecimal.ZERO;
        if (end - start < threshold) {
            for (long i = start; i <= end; i++) {
                if (i % 2 == 1) {
                    pi = pi.add(BigDecimal.ONE.divide(new BigDecimal(2 * i - 1), mc));
                } else {
                    pi = pi.subtract(BigDecimal.ONE.divide(new BigDecimal(2 * i - 1), mc));
                }
            }
            pi = pi.multiply(new BigDecimal(4), mc);
        } else {
            long middle = (start + end) / 2;
            Pi left = new Pi(start, middle);
            Pi right = new Pi(middle + 1, end);
            left.fork();
            right.fork();
            pi = left.join().add(right.join());
        }
        return pi;
    }
}

ForkJoinPool forkJoinPool = new ForkJoinPool();
long begin = System.currentTimeMillis();
System.out.println(forkJoinPool.submit(new Pi(10000000)).get());
long end = System.currentTimeMillis();
System.out.println("Time:" + (end - begin));

Output:

3.14159255358979323846289338327950288107216939937520113347494458689766015628670236776865975935664343500149358
Time:2053

Time reduced by 1 second

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

推荐阅读更多精彩内容