多线程
1. Lambda
函数式接口的定义:
任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。
例如:
public interface Runnable{ public abstract void run(); }
对于函数式接口,我们可以通过lambda表达式来创建该接口的对象。
Lambda实现案例:
new Thread(()-> System.out,println("多线程学习。。。")).start
2. 线程状态
新建、就绪状态、运行状态、阻塞状态、死亡状态
线程进入死亡状态就不能在运行了。
3.守护线程
线程分为用户线程和守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
如后台记录操作日志,监控内存,垃圾回收等待...
4.死锁
多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而两个或多个线程都在等待对方释放资源,都停止执行的情形。(说人话:多个线程互相抱着对面的资源,然后形成僵持)
5.Synchronized与Lock的对比
Lock是显示锁(手动开启和关闭锁)synchronized是隐式锁,出了作用域自动发释放。
Lock只有代码块锁,synchronized有代码块锁和方法锁
使用Lock锁,JVM将花费较少的时间来调度程序
优先使用顺序::
Lock > 同步代码块(已经进入了方法体,分配了相应的资源) > 同步方法(在方法体之外)
6.线程协作
生产者消费者模式(它是一个问题,并不是23中设计模式之一)
解决方法:
1.管程法
在生产者和消费者中间添加一个容器
package gaoji; public class Test { public static void main(String[] args) { SynContainer synContainer = new SynContainer(); new Producer(synContainer).start(); new Consumer(synContainer).start(); } } class Producer extends Thread{ SynContainer synContainer; public Producer(SynContainer synContainer){ this.synContainer = synContainer; } @Override public void run() { for (int i = 1; i <= 100; i++) { System.out.println("生产了"+i+"只鸡"); try { synContainer.push(new Chicken(i)); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } class Consumer extends Thread{ SynContainer synContainer; public Consumer(SynContainer synContainer){ this.synContainer = synContainer; } @Override public void run() { for (int i = 1; i <= 100; i++) { try { System.out.println("消费者消费了"+synContainer.pop().id+"只鸡"); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } class Chicken{ int id; public Chicken(int id) { this.id = id; } } class SynContainer{ Chicken[] chickens = new Chicken[10]; int count = 0; //生产者搞生产中 public synchronized void push(Chicken chicken) throws InterruptedException { if(count == chickens.length){ //通知消费者消费,本方法待机别搞生产了,再搞就爆仓了 this.wait(); } //容器没有满,继续搞生产 chickens[count] = chicken; count++; this.notifyAll(); } //消费者消费中 public synchronized Chicken pop() throws InterruptedException { //判断一下能不能消费先 if(count == 0){ //潇洒不了了,等待生产者搞生产 this.wait(); } //嘎嘎潇洒 count--;//数组的索引是0-9,数组的长度是10 Chicken chicken = chickens[count]; this.notifyAll(); return chicken; } }
2.信号灯法
设置一个信号,通过信号控制(例如用Boolean作信号进行控制)
7.线程池
1.使用线程池的好处:
1.提高响应速度(减少创建线程的时间)
2.降低资源消耗(重复利用线程池中的线程,不需要每次都创建)
3.便于线程管理
2. JDK 5.0起提供了线程池相关的API : ExecutorService 和 EXecutors
ExecutorService :真正的线程池接口。常见子类 ThreadPoolExecutor:
-
void execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnable
2.<T>Future<T> submit(Callable<T> task):执行任务,有返回值,一般用来执行Callable
-
void shutdown:关闭连接池
EXecutors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池