本帖最后由 小石姐姐 于 2018-8-9 11:30 编辑
等待与唤醒机制: 一个线程进行了规定操作后, 就进入等待状态( wait() ), 等待其他线程执行完他们的指定代码过后, 再将其唤醒( notify()) 在有多个线程进行等待时, 如果需要, 可以使用 notifyAll() 来唤醒所有的等待线程 wait/notify 就是线程间的一种协作机制, 用于解决线程间通信的问题 等待唤醒中的方法 java.lang.Object类: // 成员方法 (只能通过"锁对象"调用)
[AppleScript] 纯文本查看 复制代码 wait():让使用该锁的线程进入无限等待状态,直到有其他线程通过相同的锁对象唤醒(notify/notifyAll)
notify():随机唤醒一个处于等待状态的一个线程
notifyAll():唤醒所有在同一个锁对象上处于等待状态的线程 锁对象必须是多个线程共同的唯一一个 方法只能通过”锁对象”调用 从waiting恢复过来的线程 如果获取不到锁,进入BLOCKED 锁阻塞状态 如果获取到锁,进入RUNNABLE 可运行状态 调用 wait() 和 notify() 需要注意的细节: [AppleScript] 纯文本查看 复制代码 1. wait() 与 notify() 必须要由"同一个锁对象"调用
因为对应的锁对象可以通过 notify() 唤醒使用同一个锁对象调用的 wait() 后的线程
2. wait() 与 notify() 是属于Object类的方法
因为锁对象可以是任意对象, 而任意对象的所属类都是继承了Object类的
3. wait() 与 notify() 必须要在"同步代码块"或者是"同步方法"中使用
因为必须要通过锁对象调用这2个方法 线程池 普通创建线程方式的缺点: "创建"线程和"销毁"线程都是比较占用内存和CPU的操作. 对于一些数量多, 执行时间短的任务, 频繁的创建和销毁线程来执行, 会降低程序运行效率. 线程池概念: 一个容纳多个线程的容器 线程池可以解决的问题: 其中的线程可以反复使用, 省去了频繁创建线程对象的操作, 无需反复创建线程而消耗过多资源 线程池的工作原理: 提前创建好多个线程对象, 放在集合中. 多个任务来了反复使用这些线程对象来执行 线程池的代码实现 [AppleScript] 纯文本查看 复制代码 java.util.concurrent.Executors类: 线程池工厂类, 用于管理线程池 // 静态方法:
[AppleScript] 纯文本查看 复制代码 static ExecutorService newFixedThreadPool(int nThreads): 创建固定数量线程的线程池(常用)
java.util.concurrent.ExecutorService接口: 真正执行任务的线程池服务 // 成员方法:
[Java] 纯文本查看 复制代码 Future submit(Runnable task): 提交一个Runnable任务
void shutdown(): 通知线程执行完任务后关闭. 如不调此方法, 则线程执行完任务后仍在运行以 便重复使用 线程池的创建和使用步骤Executors类 [Java] 纯文本查看 复制代码 1. 使用Executors的静态方法 newFixedThreadPool(int nThreads) 创建线程池ExecutorService
例ExecutorService executorService = Executors.newFixedThreadPool(2);
2. 创建一个任务类, 实现Runnable接口, 重写run()方法
3. 调用ExecutorService对象的 submit(Runnable task) 方法, 传递任务给线程池, 执行任务
例:executorService.submit(new RunnableImpl());
4. 调用ExecutorService对象的 shutdown() 方法, 销毁线程池 (不建议执行)
例:executorService.shutdown(); 函数式编程思想:Lambda表达式 面向对象:强调用什么对象做什么事(注重语法形式) 函数式:强调做事(不在乎对象是谁,重写什么方法) 优点:简化代码编写 Lambda表达式 [Java] 纯文本查看 复制代码
( ) ‐> System.out.println(“多线程任务执行!”); Lambda标准格式 三部分组成 一些参数( ) 接口中抽象方法的参数列表. 没参数就空着; 有参数就写, 多个参数用逗号分隔 一个箭头-> 将参数传递给方法体 一段代码{} 重写接口抽象方法的方法体 标准格式为: (参数列表) - > { 一段代码 }; 解释说明格式: ( ):接口中抽象方法的参数列表,没有参数,就空着,有参数就写,多个参数用逗号分隔 -> 将参数传递给方法体 { }:重写接口的抽闲个方法的方法体 例: [Java] 纯文本查看 复制代码 new Thread(()->{
System.out.println(Thread.currentThread().getName() + "新线程 创建了");
}).start(); Lambda代替函数式接口的匿名内部类 Lambda 使用前提 1. 使用Lambda必须具有函数式接口,且要求接口中有且仅有一个抽象方法。(也称为"函数式接口") 无论是JDK内置的 Runnable 、 Comparator 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。 2. 使用Lambda必须具有上下文推断。 也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。 (简而言之: 作为参数类型的接口, 必须是函数式接口) Lambda 省略格式 省略原则:可推导的都可省略 (凡是能根据前后代码能猜测出来的代码, 都可以省略不写) 可以省略的内容: 1(参数列表):括号中参数列表的数据类型,可以省略不写 2(参数列表):括号中的参数如果只有一个,那么类型和( )都可以省略 3{一些代码}:如果只有一条代码,则”大括号”,”return”,”分号”都可以”一起省略”
|