多线程和Lambda表达式

7月20日知识点

今天的主要内容——线程

  • 线程

    • 线程的基本概念

      • 线程与进程的区别
    • 线程的两种创建方式(掌握)

      • 注意线程两种创建方式的区别

      • 内部类实现线程创建

    • 线程的第三种创建方式——实现Callable接口

    • Thread类中的方法使用

      • getName()
      • setName()
      • currentthread()
      • sleep
      • join
      • wait
      • yield
      • setDaemon
    • 线程的同步(掌握)

      • 同步代码块

      • 同步方法

    • 多线程(线程安全问题)(掌握)

    • 线程的死锁(了解)

    • 多线程和队列实现买卖票(掌握)

  • Lambda表达式

    • lambda表达式的几种方式
    • lambda表达式用途

线程

1. 线程的基本概念

  • image
  • 1.什么是线程

    • 线程是程序执行的一条路径, 一个进程中可以包含多条线程
    • 多线程并发执行可以提高程序的效率, 可以同时完成多项工作
  • 进程:其实是一个静态的概念
    * 我们平时所说的进程开始执行,指的是:进程中主线程开始执行了,即main方法开始执行了

  • 计算机中实际运行的都是线程。

  • 操作系统是支持多线程,多进程的,系统是同时执行多个线程的

  • CPU的执行:交替执行众多线程,因为速度快,表面上是同时执行多个线程,其实不是的。

注:

① Java的线程是通过java.lang.Thread类来实现的

② VM启动时会有一个主方法(main方法)所定义的线程

③ 可通过创建Thread的实例来创建新的线程

④ 每个线程都是通过某个特定的Thread对象所对应的run方法来完成其操作的,方法run()称为线程体

⑤ 通过调用Thread类中的start()方法来启动一个线程。

2. 多线程(多线程并行和并发的区别)(了解)

  • 并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU)
  • 并发是指两个任务都请求运行,而处理器只能按受一个任务,就把这两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行。
  • 比如我跟两个网友聊天,左手操作一个电脑跟甲聊,同时右手用另一台电脑跟乙聊天,这就叫并行。
  • 如果用一台电脑我先给甲发个消息,然后立刻再给乙发消息,然后再跟甲聊,再跟乙聊。这就叫并发。

3. 多线程(Java程序运行原理和JVM的启动是多线程的吗)(了解)

  • A:Java程序运行原理

    • Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main 方法。
  • B:JVM的启动是多线程的吗

    • JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。

    • 运行程序证明JVM的多线程

        public class TestJVMMultiThread {   
            public static void main(String[] args) {
                //创建垃圾对象观察垃圾回收线程
                for(int i = 0;i < 100;i++) {
                    new Test();     
                }
                
                for(int i = 0;i < 100;i++) {
                    System.out.println("主线程在执行");   
                }       
            }   
        }
        
        class Test{
            
            @Override
            public void finalize(){
                System.out.println("垃圾回收线程在执行");
            }   
        }
      

4. 线程的两种创建方式

image
image
image
image

3. 线程两种创建方式程序

  • 创建线程程序1:

    image
    image
    • 用lambda表达式简写线程启动过程

        public class TestLambda {
            public static void main(String[] args) {
                
                System.out.println("哈哈哈哈我在测试啊");
                
                Runnable runner = ()->{
                    StringBuffer s = new StringBuffer();
                    
                    for(int i= 0;i < 10;i++)
                        System.out.println(s.append("haha"));
                };
                
                new Thread(runner).start();  //注意:同一个线程不可以启动多次
                
                System.out.println("任务完成");
            }   
        }
        /*
         *  在JDK1.8中输出结果为:
         *  ------------------------------------------
         *  哈哈哈哈我在测试啊
            任务完成
            haha
            hahahaha
            hahahahahaha
            hahahahahahahaha
            hahahahahahahahahaha
            hahahahahahahahahahahaha
            hahahahahahahahahahahahahaha
            hahahahahahahahahahahahahahahaha
            hahahahahahahahahahahahahahahahahaha
            hahahahahahahahahahahahahahahahahahahaha
            ------------------------------------------
         * */
      
  • 创建线程程序2:

    image
    • 此时Runner线程和main线程交替运行
* 能使用接口实现线程就不要用继承,因为用了接口以后还可以继承和实现其它接口,而如果只继承会比较死板

4. 创建线程的两种方式的区别(掌握)

  • 查看源码的区别:
    • a.继承Thread : 由于子类重写了Thread类的run(), 当调用start()时, 直接找子类的run()方法
    • b.实现Runnable : 构造函数中传入了Runnable的引用, 成员变量记住了它, start()调用run()方法时内部判断成员变量Runnable的引用是否为空, 不为空编译时看的是Runnable的run(),运行时执行的是子类的run()方法
      • Thread类中的run()源码为:
            public void run() {
                if (target != null) {
                    target.run();
                }
            }

5. 匿名内部类实现线程

  • 继承Thread类

      new Thread() {                                 //1.继承Thread类
              public void run(){                      //2.重写run方法
                  for(int i = 0;i < 1000;i++) {
                      System.out.println("aaaaaa");
                  }
              }
          }.start();                                  //3.开启线程
    
  • 实现Runnable接口

      new Thread(new Runnable() {                 //1.将Runnable子类对象传递给Thread构造方法
          public void run(){                      //2.重写run方法
              for(int i = 0;i < 1000;i++) {               
                  System.out.println("bb");
              }
          }           
      }).start();                                 //3.开启线程
    

6. 创建线程的两种方式的区别(掌握)

  • 继承Thread
    • 好处是:可以直接使用Thread类中的方法,代码简单
* 弊端是:如果已经有了父类,就不能用这种方法
  • 实现Runnable接口
    • 好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的
* 弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂

7. 线程的第三种创建方式

  • 使用Callable接口_java.util.concurrent

    image
    • Callable接口与Runnable接口的区别:
      • Runnable没有返回值一说,而且run()方法并不抛出异常
      • Callable中的call方法具有返回值
      • Callable之所以有返回值,也是因为实现了泛型,而Runnable接口不存在泛型
7.1 FutureTask类的学习——java.util.concurrent.FutureTask<V>
image
  • FutureTask的构造器
image
  • 此时可理解为:FutureTask的作用就是接收一个实现了Callable接口的实现类对象

  • 此时注意到FutureTask实现了Runnable接口

    • 也就是说可以把FutureTask的实现类对象传入到Runnable类型
  • 而Thread类中的构造器的参数为Runnable类型
  • 因此梳理后可知

    ①先实现Callable接口

      class myThread_3 implements Callable<String>{
          @Override
          public String call() throws Exception {
              return "线程创建成功";
          }
      }
    

    ②将Callable实现类对象传给FutureTask构造器

      FutureTask<String> ft = new FutureTask<>(new myThread_3());
    
      * 因为FutureTask实现了Runnable接口,因此以下代码也正确
    
          Runnable runner = new FutureTask<String>(new myThread_3());
          * 接口引用指向实现类对象
          * 但是此时runner只能访问Runnable中方法,不可以访问FutureTask中的方法
    

    ③创建线程并启动

      new Thread(ft).start();
    

    ④使用FutureTask类中方法

      public V get() throws InterruptedException,ExecutionException
    
      通过Thread启动线程之后 可以通过FutureTask存在get方法可以取得call()方法中的返回值
    
      /*用到Callable有什么用?只是为了返回一个值?执行线程的代码run用什么代替?*/
      /*回答:此时线程启动start()方法调用的是call()方法,将需要执行的代码放到call()方法中,同时call()方法的特点在于有返回值*/
    
  • 程序

      public class TestCallable{
          public static void main(String[] args) {
              FutureTask<String> ft = new FutureTask<String>(new myThread_3());
              
              new Thread(ft).start();  //此时的启动需要调用的是call()方法      
              String result = null;
      
              try {
                  result = ft.get();
              } catch (InterruptedException | ExecutionException e) {
                  e.printStackTrace();
              }       
              System.out.println(result);     
              
          }   
      }
      
      class myThread_3 implements Callable<String>{
      
          @Override   
          public String call() throws Exception {     
              System.out.println("此时start()方法调用的是call()方法");
              return "线程创建成功";
          }
      }
    
      /*  在JDK1.8中输出结果为:
       *  ----------------------------
       *  此时start()方法调用的是call()方法
          线程创建成功
          ----------------------------
       * */
    

8. 多线程(获取名字和设置名字)(掌握)

  • 获取名字

    • 通过getName()方法获取线程对象的名字

        public final String getName();
      
  • 设置名字

    • 通过构造函数可以传入String类型的名字

        public Thread(String name)
      
        public Thread(Runnable target,String name)  
      
    • 通过setName(String)方法可以设置线程对象的名字

        public final void setName(String name);
      
  • 程序实现

      new Thread("线程一") {             //设置线程名字
              public void run() {
                  for(int i = 0;i < 100;i++) {
                      System.out.println(this.getName() + "....aaaa");   //获取线程名字
                  }
              }
          }.start();
      
      new Thread("线程二") {                 //设置线程名字
          public void run() {
              for(int i = 0;i < 100;i++) {
                  System.out.println(this.getName() + "....bb");
              }
          }
      }.start();
      
      new Thread() {
          public void run() {
              this.setName("线程3");       //设置线程名字
              
              for(int i = 0;i < 100;i++) {
                  System.out.println(this.getName() + "....哈哈");
              }
          }
      }.start();
    

9. 多线程(获取当前线程的对象)(掌握)

public static Thread currentThread()

Thread.currentthread();——注意返回值是Thread

//匿名内部类实现当前线程对象的获取
new Thread() {          
    public void run() {
        this.setName("线程A");
        
        for(int i = 0;i < 1000;i++) {
            System.out.println( Thread.currentThread().getName() + "....aaaa");
        }
    }
    
}.start();

new Thread(new Runnable() {
    public void run() {
        for(int i = 0;i < 1000;i++) {
            System.out.println( Thread.currentThread().getName() + "....bb");
        }
    }
},"线程B").start();       

}

10. 多线程(休眠线程)(掌握)

  • public static void sleep(long millis) throws InterruptedException

    • 抛出InterruptionException
        public class TestSleepOfThread {
            public static void main(String[] args) {
                
                Runnable r = ()->{
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    
                    System.out.println("Thread A");
                };
                
                new Thread(r).start();
                
                System.out.println("main Thread");
            }
        }
        /*
         * 在JDK1.8中输出结果为:
         * -------------
         * main Thread
           Thread A
           -------------
         * */

11. 多线程(守护线程)(掌握)

  • setDaemon(), 设置一个线程为守护线程, 该线程不会单独执行, 当其他非守护线程都执行结束后, 自动退出

  • public final void setDaemon(boolean on)

    • on - if true, marks this thread as a daemon thread

        public class TestSetDaemon {
            public static void main(String[] args) {
                Thread t1 = new Thread("线程A") {
                    public void run() {
                        for(int i = 0;i < 2;i++) {
                            System.out.println(Thread.currentThread().getName() + "....aaaa");
                        }
                    }
                };
                
                Thread t2 = new Thread(new Runnable() {
                    public void run() {
                        for(int i = 0;i < 50;i++) {
                            System.out.println(Thread.currentThread().getName() + "....bb");
                        }
                    }
                },"线程B");
                
                t2.setDaemon(true);          //将t2设置为守护线程
                
                t1.start();
                t2.start();
                
            }
        }
        /*
         *  在JDK1.8中输出结果为:
         *  ------------------------
         *  线程A....aaaa
            线程B....bb
            线程A....aaaa
            线程B....bb      //存在时间缓冲问题
            线程B....bb
            线程B....bb
            线程B....bb
            线程B....bb
            线程B....bb
            线程B....bb
         * */
      

12. 多线程(加入线程)(掌握)

  • join(), 当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续

  • join(int), 可以等待指定的毫秒之后继续

  • public final void join() throws InterruptedException

      public class TestJoin {
          public static void main(String[] args) {
              
              Thread t1 = new Thread("线程A") {
                  public void run() {
                      for(int i = 0;i < 100;i++) {
                          System.out.println(getName() + "....aaaaaaa");
                      }
                  }
              };
              
              Runnable r = ()->{
                  for(int i = 0;i < 50;i++) {
                      
                      if(i == 2) {
                          try {
                              t1.join();
                              //t1.join(1000); t1插队执行1秒后,t1和t2线程再抢占CPU交替执行
                          } catch (InterruptedException e) {
                              e.printStackTrace();
                          }
                      }               
                      
                      System.out.println(Thread.currentThread().getName() + "....bb");
                  }
              };
              
              t1.start();
              new Thread(r).start();
          }
      }
    

13. 多线程(礼让线程)(了解)

  • yield让出cpu

14. 多线程(设置线程的优先级)(了解)

  • setPriority()设置线程的优先级

15. 多线程(同步代码块)(掌握)

  • 1.什么情况下需要同步
    • 当多线程并发, 有多段代码同时执行时, 我们希望某一段代码执行的过程中CPU不要切换到其他线程工作. 这时就需要同步.
    • 如果两段代码是同步的, 那么同一时间只能执行一段, 在一段代码没执行结束之前, 不会执行另外一段代码.
  • 2.同步代码块
    • 使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块

    • 锁对象不可以用匿名对象,因为匿名对象不是同一个对象

    • 多个同步代码块如果使用相同的锁对象, 那么他们就是同步的

        public class TestTickets_2 {
            public static void main(String[] args) {
                MyThread_6 myt = new MyThread_6();
                
                new Thread(myt,"线程A").start();
                new Thread(myt,"线程B").start();
            }
        }
        
        class MyThread_6 implements Runnable{
        
            private int ticket = 5;
            
            @Override
            public void run() {
                    while(true) {
                        if(this.ticket > 0) {
                            System.out.println(Thread.currentThread().getName() + "开始卖票 = " + ticket--);
                        }
                        else {
                            System.out.println("票已经卖完");
                            break;
                        }
                    }   
                }   
        }
      

16. 多线程(同步方法)(掌握)

public class TestSynchronized_2 {
    
    public static void main(String[] args) {
        Printer_2 p = new Printer_2();
        
        Runnable r = ()->{
            for(int i = 0;i < 100;i++) {
                p.print1();
            }
        };
        
        Thread t2 = new Thread() {
            public void run() {
                for(int i = 0;i < 100;i++) {
                    p.print2();
                }
            }
        };
        
        new Thread(r).start();
        t2.start();     
    }
}

class Printer_2{
    public synchronized void print1() {
        System.out.print("早");
        System.out.print("上");
        System.out.print("好");
        System.out.print("啊");
        System.out.print("\r\n");
    }
    
    public void print2() {
        synchronized(this) {
            System.out.print("河");
            System.out.print("正");
            System.out.print("宇");
            System.out.print("好");
            System.out.print("帅");  
            System.out.print("\r\n");
        }       
    }   
}

17. 多线程(线程安全问题)(掌握)

  • 多线程并发操作同一数据时, 就有可能出现线程安全问题

  • 使用同步技术可以解决这种问题, 把操作数据的代码进行同步, 不要多个线程一起操作

      /*
       *  铁路售票,一共100张,通过四个窗口卖完 
       * */
      public class TestSynchronized_3 {
          public static void main(String[] args) {
              new Ticket().start();
              new Ticket().start();
              new Ticket().start();
          }   
      }
      
      class Ticket extends Thread{
          private static int ticket = 100;
          
          public void run() {
              while(true) {
                  //synchronized(this)
                  synchronized(Ticket.class) {
                      if(ticket == 0) {
                          break;
                      }
                      
                      System.out.println(getName() + "这是第" + ticket-- + "号票");
                  }
              }
          }
      }
    

18. 多线程(火车站卖票的例子用实现Runnable接口)(掌握)

public class TestSynchronized_4 {
    public static void main(String[] args) {
        Ticket_2 t = new Ticket_2();
        
        new Thread(t,"线程A").start();
        new Thread(t,"线程B").start();
        new Thread(t,"线程C").start();
        new Thread(t,"线程D").start();
    }
}

class Ticket_2 implements Runnable{
    private int ticket = 100;  //此时ticket不需要设置为共享,因为均为同一对象
    
    @Override
    public void run() {
        while(true) {
            synchronized(this) {
                if(ticket == 0) {
                    break;
                }
                
                System.out.println(Thread.currentThread().getName() + " 这是第" + ticket-- + "号票");
            }
        }
    }
}

19. 多线程(死锁)(了解)

public class TestDeadLock {
    private static Object o1 = new Object();
    private static Object o2 = new Object();
    
    
    public static void main(String[] args) {
        new Thread("线程A") {
            public void run() {
                while(true) {
                    synchronized(o1) {
                        System.out.println(getName() + "正在使用o1,等待o2");
                        synchronized(o2) {
                            System.out.println(getName()  +"等到o2,执行成功");
                        }
                    }
                }               
            }
        }.start();
        
        new Thread("线程B") {
            public void run() {
                while(true) {
                    synchronized(o2) {
                        System.out.println(getName() + "正在使用o2,等待o1");
                        synchronized(o1) {
                            System.out.println(getName() + "等到o1,执行成功");
                        }
                    }
                }               
            }
        }.start();
    }
}
/*
 *  在JDK1.8中输出结果为:
 *  ----------------------
    线程A正在使用o1,等待o2
    线程A等到o2,执行成功
    线程A正在使用o1,等待o2
    线程B正在使用o2,等待o1
    -------------------------
 * */
  • 因此:synchronized不要嵌套使用,容易出错

20. 多线程和队列实现买卖票

Queue接口
public interface Queue {
    
    public void append(Object obj)throws Exception;
    
    public Object delete()throws Exception;

    public Object getFront()throws Exception;   
    
    public boolean isEmpty();
}
Class MyQueue
public class MyQueue implements Queue{
        
        //1 设置队列的默认长度
        
        static final int DEFAULT_SIZE=10;  //默认长度为10
        
        //2 设置队头
        
        int front; 
        
        //3 设置队尾
        
        int rear;
        
        //4 定义统计元素的变量
        
        int count;
        
        //5 队的最大长度
        
        int maxSize;
        
        Object[] queue;  //设置队列
        
        //空构造
        public MyQueue() {
            
            this.init(DEFAULT_SIZE);  //用户给定长度 默认长度为10
        }
        
        
        //有参数的构造
        public MyQueue(int size) {
            
            this.init(size);  //开辟用户给定的长度
        }
        
        /**
         * 初始化方法
         * @param size
         */
        public void init(int size) {
            
            //初始化属性
            this.maxSize=size;  //外部传进来的size
            
            //空队列
            front=rear=0;
            
            count=0;
            
            queue=new Object[size];
        }
        
        @Override
        public void append(Object obj) throws Exception {
            // TODO Auto-generated method stub
            //首先队列是否已满
            if(count>0&&front==rear) {  //判断队列是否已满
                
                throw new Exception("队列已满");
            }
            
            this.queue[rear]=obj;
            rear=(rear+1)%maxSize;
            count++;
        }

        @Override
        public Object delete() throws Exception {
            // TODO Auto-generated method stub
            if(this.isEmpty()) {
                
                throw new Exception("队列为空队");
            }
            
            Object obj=this.queue[front];
            front=(front+1)%maxSize;
            count--;
            
            return obj;
            
        }

        @Override
        public Object getFront() throws Exception {
            // TODO Auto-generated method stub
            if(!this.isEmpty()) {
                
                return this.queue[front];
            }
            return null;
        }

        @Override
        public boolean isEmpty() {
            // TODO Auto-generated method stub
            return this.count==0;
        }
    }
Class WindowQueue
public class WindowQueue { //卖票的窗口

    //定义卖票队列
    
    int maxSize=10;
    
    MyQueue queue=new MyQueue(maxSize);
    
    int num=0; //最多卖100张票
    
    boolean flag=true ; //判断是否继续卖票
    
    
    //排队买票
    public synchronized void producer()throws Exception{
        
        if(this.queue.count<maxSize) {
            
            this.queue.append(num++); //等待买票的数量++
            System.out.println("第"+num+"个客户排队买票");
            this.notifyAll(); //唤醒等待的线程
        }else {
            
            System.out.println("队列已满 请等待");
            this.wait(); 
        }
    }
    
    
    //卖票
    public synchronized void consumer()throws Exception{
        
        if(this.queue.count>0) {
            Object obj=this.queue.delete();  //出队
            int temp=Integer.parseInt(obj.toString());
            System.out.println("第"+(temp+1)+"个客户买到票离开队列");
            
            //如果当前的队列为空 并且卖出票数大于100
            if(this.queue.isEmpty()&&this.num>=100) {
                
                this.flag=false;
            }
            this.notifyAll(); //唤醒等待的线程
        }else {
            
            System.out.println("队列已空 请等待");
            this.wait();
        }
    }
}
Class Producer
public class Producer implements Runnable{

    WindowQueue queue;
    
    public Producer(WindowQueue queue) {
        
        this.queue=queue;
    }
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(queue.num<100) {  //必须小于100张票 才可以买票
        try {
            Thread.sleep(1000);
            queue.producer();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        }
    }

}
Class Consumer
public class Consumer implements Runnable{
    
    WindowQueue queue;
    
    public Consumer(WindowQueue queue) {
        
        this.queue=queue;
    }
    
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(queue.flag) {  //如果队列为空 并且票数大于100 就不会卖票了
            
            try {
                Thread.sleep(1000);
                queue.consumer();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}
Class QueueTest
public class QueueTest {        
    public static void main(String[] args) throws Exception {       
        WindowQueue queue=new WindowQueue();
        Producer p=new Producer(queue);
        
        Consumer con=new Consumer(queue);
        
        //以上的代码一定要注意 传入的是同一个对象
        
        Thread t1=new Thread(p);
        
        Thread t2=new Thread(con);
        
        
        t1.start();
        
        t2.start();
    }
}

Lambda表达式

  • Lambda表达式的形式

    参数,箭头(→)以及一个表示

  • Lambda适用于接口中一个抽象方法时候使用

  • 举例1——函数式接口使用

      Runnable runner = ()->{
          StringBuffer s = new StringBuffer();
          
          for(int i= 0;i < 10;i++)
              System.out.println(s.append("haha"));
      };
    
  • 举例2——只有一个抽象方法的接口的实现类的使用

      Thread t1 = new Thread(()->{
          StringBuffer s = new StringBuffer();
          
          for(int i= 0;i < 10;i++)
              System.out.println(s.append("haha"));
      });
    
  • 区别于匿名内部类——需要写出方法声明

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

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,558评论 18 399
  • Java多线程学习 [-] 一扩展javalangThread类 二实现javalangRunnable接口 三T...
    影驰阅读 2,948评论 1 18
  • 本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。 首先讲...
    李欣阳阅读 2,436评论 1 15
  • 老二摸着黑下了床,为了使自己的脚步声音听起来很轻,他并没有穿鞋,哪怕是拉开插销的动作看起来都细微无比,门轻轻的打开...
    秦约取阅读 201评论 0 0
  • 编辑区最大化的时候控制台有新的输出的时候会弹窗很烦人, command+,跳出设置菜单然后到Run/debug--...
    RobertCrazying阅读 200评论 0 0