线程的状态图线程的状态新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked、Waiting、Timed_Waiting)、死亡状态(Terminated)。线程的生命周期新建状态 – 就绪状态 调用线程的start()方法。就绪状态-运行状态 JVM按照线程调度策略。运行状态-阻塞状态 等待事件。阻塞状态-就绪状态 唤醒。运行状态-死亡状态 线程结束。等待唤醒机制什么是等待唤醒机制在一个线程进行了规定操作后就进入等待状态wait() 等待其他线程执行完他们的指定代码过后 再将其唤醒notify();在有多个线程进行等待时 如果需要可以使用 notifyAll()来唤醒所有的等待线程。wait/notify 就是线程间的一种协作机制。等待唤醒机制就是用于解决线程间通信的问题的使用到的3个方法的含义如下wait线程不再活动不再参与调度进入 wait set 中因此不会浪费 CPU 资源也不会去竞争锁了这时的线程状态即是 WAITING。它还要等着别的线程执行一个特别的动作也即是“通知notify”在这个对象上等待的线程从wait set 中释放出来重新进入到调度队列ready queue中notify则选取所通知对象的 wait set 中的一个线程释放例如餐馆有空位置后等候就餐最久的顾客最先入座。notifyAll则释放所通知对象的 wait set 上的全部线程。调用wait和notify方法需要注意的细节wait方法与notify方法必须要由同一个锁对象调用。因为对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。wait方法与notify方法是属于Object类的方法的。因为锁对象可以是任意对象而任意对象的所属类都是继承了Object类的。wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为必须要通过锁对象调用这2个方法。练习package cn.anxincao.threadtest1; public class LeftRight { boolean flag false; class Left extends Thread{ // Override public void run() { for (int i 0; i 50; i) { synchronized (LeftRight.class) { while (flag) { try { LeftRight.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.printf(%s\n, 左脚一步); flag true; LeftRight.class.notify(); } } } } class Right extends Thread{ Override public void run() { for (int i 0; i 50; i) { synchronized (LeftRight.class){ while(!flag){ //flag为false时这段代码才会执行。 try{ LeftRight.class.wait(); }catch (InterruptedException e){ e.printStackTrace(); } } System.out.printf(%30s\n,右脚一步! ); flag false; //下一个循环就等待 LeftRight.class.notify(); // 唤醒同一个对象的另一个线程 } } } } public static void main(String[] args) { LeftRight lf new LeftRight(); lf.new Left().start(); lf.new Right().start(); } }线程池线程思想概述如果并发的线程数量很多并且每个线程都是执行一个时间很短的任务就结束了这样频繁创建线程就会大大降低系统的效率因为频繁创建线程和销毁线程需要时间。在Java中可以通过线程池使得线程可以复用就是执行完一个任务并不被销毁而是可以继续执行其他的任务。线程池JDK1.5之后提供的java.util.concurrent.Executors线程池的工厂类用来生成线程池Executors类中的静态方法static ExecutorService newFixedThreadPoolint nThreads创建一个可重用固定线程数的线程池参数int nThreads创建线程池中包含的线程数量返回值ExecutorService接口返回的是ExecutorService接口的实现类对象我们可以使用ExecutorService接口接收面向接口编程java.util.concurrent.Executorservice线程池接口用来从线程池中获取线程调用start方法执行线程任务submitRunnable tosk提交一个Runnable任务用于执行关闭/销毁线程池的方法void shutdown()线程池的使用步骤1.使用线程池的工厂类Executors里边提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池2.创建一个类实现Runnable接口重写run方法设置线程任务3.调用ExecutorService中的方法submit传递线程任务实现类开启线程执行run方法4.调用ExecutorService中的方法shutdown销毁线程池不建议执行import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Threadpool { public static void main(String[] args) { // 创建线程池对象 ExecutorService service Executors.newFixedThreadPool(2);//包含2个线程对象 // 创建Runnable实例对象 Runnable r new Runnable() { Override public void run() { System.out.println(我要一个教练); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(教练来了 Thread.currentThread().getName()); System.out.println(教我游泳,交完后教练回到了游泳池); } }; //自己创建线程对象的方式 // Thread t new Thread(r); // t.start(); ‐‐‐ 调用MyRunnable中的run() // 从线程池中获取线程对象,然后调用MyRunnable中的run() service.submit(r); // 再获取个线程对象调用MyRunnable中的run() service.submit(r); service.submit(r); // 注意submit方法调用结束后程序并不终止是因为线程池控制了线程的关闭。 // 将使用完的线程又归还到了线程池中 // 关闭线程池 service.shutdown(); } }Lambda表达式在数学中函数就是有输入量、输出量的一套计算方案也就是“拿什么东西做什么事情”。相对而言面向对象过分强调“必须通过对象的形式来做事情”而函数式思想则尽量忽略面向对象的复杂语法一—强调做什么而不是以什么形式做。面向对象的思想做一件事情找一个能解决这个事情的对象调用对象的方法完成事情.函数式编程思想只要能获取到结果谁去做的怎么做的都不重要重视的是结果不重视过程。箭头代表传递。本质是将run方法体内的代码传递给Thread类。练习public class test1 { public static void main(String[] args) { //使用匿名内部类的方式实现多线程 new Thread(new Runnable() { Override public void run() { System.out.println(Thread.currentThread().getName()新线程创建了); } }).start(); //使用Lambda 表达式实现多线程 new Thread(()-{ System.out.println(Thread.currentThread().getName()新线程创建了); }).start(); } }匿名内部类的好处与弊端一方面匿名内部类可以帮我们省去实现类的定义另一方面匿名内部类的语法——确实太复杂了语义分析仔细分析该代码中的语义Runnable接口只有一个run方法的定义·public abstract void run即制定了一种做事情的方案其实就是一个函数·无参数不需要任何条件即可执行该方案。·无返回值该方案不产生任何结果。·代码块方法体该方案的具体执行步骤。同样的语义体现在Lambda 语法中要更加简单- System.out.println“多线程任务执行Lambda表达式的标准格式由三部分组成a.一些参数b.一个箭头c.一段代码格式参数列表-{一些重写方法的代码}解释说明格式接口中抽象方法的参数列表没有参数就空着有参数就写出参数多个参数使用逗号分隔-传递的意思把参数传递给方法体{}{ }重写接口的抽象方法的方法体Lambda省略式在Lambda标准格式的基础上使用省略写法的规则为加粗样式1.小括号内参数的类型可以省略2.如果小括号内有且仅有一个参则小括号可以省略3.如果大括号内有且仅有一个语句则无论是否有返回值都可以省略大括号、return关键字及语句分号。
java线程的状态、线程池、Lambda表达式
线程的状态图线程的状态新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked、Waiting、Timed_Waiting)、死亡状态(Terminated)。线程的生命周期新建状态 – 就绪状态 调用线程的start()方法。就绪状态-运行状态 JVM按照线程调度策略。运行状态-阻塞状态 等待事件。阻塞状态-就绪状态 唤醒。运行状态-死亡状态 线程结束。等待唤醒机制什么是等待唤醒机制在一个线程进行了规定操作后就进入等待状态wait() 等待其他线程执行完他们的指定代码过后 再将其唤醒notify();在有多个线程进行等待时 如果需要可以使用 notifyAll()来唤醒所有的等待线程。wait/notify 就是线程间的一种协作机制。等待唤醒机制就是用于解决线程间通信的问题的使用到的3个方法的含义如下wait线程不再活动不再参与调度进入 wait set 中因此不会浪费 CPU 资源也不会去竞争锁了这时的线程状态即是 WAITING。它还要等着别的线程执行一个特别的动作也即是“通知notify”在这个对象上等待的线程从wait set 中释放出来重新进入到调度队列ready queue中notify则选取所通知对象的 wait set 中的一个线程释放例如餐馆有空位置后等候就餐最久的顾客最先入座。notifyAll则释放所通知对象的 wait set 上的全部线程。调用wait和notify方法需要注意的细节wait方法与notify方法必须要由同一个锁对象调用。因为对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。wait方法与notify方法是属于Object类的方法的。因为锁对象可以是任意对象而任意对象的所属类都是继承了Object类的。wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为必须要通过锁对象调用这2个方法。练习package cn.anxincao.threadtest1; public class LeftRight { boolean flag false; class Left extends Thread{ // Override public void run() { for (int i 0; i 50; i) { synchronized (LeftRight.class) { while (flag) { try { LeftRight.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.printf(%s\n, 左脚一步); flag true; LeftRight.class.notify(); } } } } class Right extends Thread{ Override public void run() { for (int i 0; i 50; i) { synchronized (LeftRight.class){ while(!flag){ //flag为false时这段代码才会执行。 try{ LeftRight.class.wait(); }catch (InterruptedException e){ e.printStackTrace(); } } System.out.printf(%30s\n,右脚一步! ); flag false; //下一个循环就等待 LeftRight.class.notify(); // 唤醒同一个对象的另一个线程 } } } } public static void main(String[] args) { LeftRight lf new LeftRight(); lf.new Left().start(); lf.new Right().start(); } }线程池线程思想概述如果并发的线程数量很多并且每个线程都是执行一个时间很短的任务就结束了这样频繁创建线程就会大大降低系统的效率因为频繁创建线程和销毁线程需要时间。在Java中可以通过线程池使得线程可以复用就是执行完一个任务并不被销毁而是可以继续执行其他的任务。线程池JDK1.5之后提供的java.util.concurrent.Executors线程池的工厂类用来生成线程池Executors类中的静态方法static ExecutorService newFixedThreadPoolint nThreads创建一个可重用固定线程数的线程池参数int nThreads创建线程池中包含的线程数量返回值ExecutorService接口返回的是ExecutorService接口的实现类对象我们可以使用ExecutorService接口接收面向接口编程java.util.concurrent.Executorservice线程池接口用来从线程池中获取线程调用start方法执行线程任务submitRunnable tosk提交一个Runnable任务用于执行关闭/销毁线程池的方法void shutdown()线程池的使用步骤1.使用线程池的工厂类Executors里边提供的静态方法newFixedThreadPool生产一个指定线程数量的线程池2.创建一个类实现Runnable接口重写run方法设置线程任务3.调用ExecutorService中的方法submit传递线程任务实现类开启线程执行run方法4.调用ExecutorService中的方法shutdown销毁线程池不建议执行import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Threadpool { public static void main(String[] args) { // 创建线程池对象 ExecutorService service Executors.newFixedThreadPool(2);//包含2个线程对象 // 创建Runnable实例对象 Runnable r new Runnable() { Override public void run() { System.out.println(我要一个教练); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(教练来了 Thread.currentThread().getName()); System.out.println(教我游泳,交完后教练回到了游泳池); } }; //自己创建线程对象的方式 // Thread t new Thread(r); // t.start(); ‐‐‐ 调用MyRunnable中的run() // 从线程池中获取线程对象,然后调用MyRunnable中的run() service.submit(r); // 再获取个线程对象调用MyRunnable中的run() service.submit(r); service.submit(r); // 注意submit方法调用结束后程序并不终止是因为线程池控制了线程的关闭。 // 将使用完的线程又归还到了线程池中 // 关闭线程池 service.shutdown(); } }Lambda表达式在数学中函数就是有输入量、输出量的一套计算方案也就是“拿什么东西做什么事情”。相对而言面向对象过分强调“必须通过对象的形式来做事情”而函数式思想则尽量忽略面向对象的复杂语法一—强调做什么而不是以什么形式做。面向对象的思想做一件事情找一个能解决这个事情的对象调用对象的方法完成事情.函数式编程思想只要能获取到结果谁去做的怎么做的都不重要重视的是结果不重视过程。箭头代表传递。本质是将run方法体内的代码传递给Thread类。练习public class test1 { public static void main(String[] args) { //使用匿名内部类的方式实现多线程 new Thread(new Runnable() { Override public void run() { System.out.println(Thread.currentThread().getName()新线程创建了); } }).start(); //使用Lambda 表达式实现多线程 new Thread(()-{ System.out.println(Thread.currentThread().getName()新线程创建了); }).start(); } }匿名内部类的好处与弊端一方面匿名内部类可以帮我们省去实现类的定义另一方面匿名内部类的语法——确实太复杂了语义分析仔细分析该代码中的语义Runnable接口只有一个run方法的定义·public abstract void run即制定了一种做事情的方案其实就是一个函数·无参数不需要任何条件即可执行该方案。·无返回值该方案不产生任何结果。·代码块方法体该方案的具体执行步骤。同样的语义体现在Lambda 语法中要更加简单- System.out.println“多线程任务执行Lambda表达式的标准格式由三部分组成a.一些参数b.一个箭头c.一段代码格式参数列表-{一些重写方法的代码}解释说明格式接口中抽象方法的参数列表没有参数就空着有参数就写出参数多个参数使用逗号分隔-传递的意思把参数传递给方法体{}{ }重写接口的抽象方法的方法体Lambda省略式在Lambda标准格式的基础上使用省略写法的规则为加粗样式1.小括号内参数的类型可以省略2.如果小括号内有且仅有一个参则小括号可以省略3.如果大括号内有且仅有一个语句则无论是否有返回值都可以省略大括号、return关键字及语句分号。