JAVA多线程编程
1.1 进程、线程、多线程
- 通过并发与并行抢占CPU资源
- Java 的多线程机制 - 通过 Java 虚拟机实现
线程分为用户线程和守护进程(如GC垃圾回收)。每个 Java 程序有一个缺省的主线程(main方法)。从 main 方法开始执行时,再创建的线程成为程序其他线程。 虚拟机在所有线程结束后才会结束 Java 程序。
1.2 线程的生命周期
- 新建状态 调用 start() 进入Runable
- Runable:
- Running <=> Ready (调度切换)
- 阻塞(中断)状态
- Timed Waiting: (限期等待)如sleep,wait,join方法
- Waiting (无限期等待)
- Blocked (阻塞状态,通过排他锁的方式实现)
- Terminated (死亡状态)
1.3 线程调度与优先级
- 抢占调度模型机制
- 优先级
- 线程优先级时一个1~10的整数,默认每个线程都会分配5
- setPriorit(int grade) 、 getPriority()
- 并不能绝对保证执行顺序,具体看CPU调度
1.4 线程创建方法
- Thread 子类 (java.lang包)
- 须重写 run 方法,其在分配CPU资源时会自动执行
- 子类.start() 调用开始运行
- Thread 类
- Thread( Runnable target )
class Demo implements Runnable{
//注意接口中的访问性不可以降低
public void run(){}
}
...
Demo demo = new Demo();
Thread mythread = new Thread(demo);
Runnable 是一个接口,实例对象指向所创建线程的目标对象,调用 start 方法后同上会自动调用 run 方法。
此处还涉及到一个静态代理的概念,如Runnable方式简介通过 Thread创建线程就是种代理。静态代理的条件及好处:
- 代理和实体类实现了同一个接口
- 使得实体类可以充分解放,交给代理完成部署,自己完成本职工作
- calloc 线程池批量注册创建线程
1.5 线程中常用方法
- run()、start()
- sleep(int millsecond) 使线程放弃CPU资源
- isAlive() 测试进程是否激活,新建+死亡 return false
- currentTread() 类方法
- interrupt()
正在执行的其他进程可使用要唤醒线程.interrupt(),通过产生异常的形式结束休眠。 如无限期等待线程可捕捉到main方法抛出的InterruptedException被唤醒而重新排队。
注:一个正在运行的线程不要再重新new了,否则先前的实体会变成垃圾且不会被垃圾回收掉,如果突然释放可能会引发错误甚至导致设备损坏
1.6 Lamda表达式
实现函数式接口,使得代码简洁。
- 变化过程:类 -> 静态内部类 -> 局部内部类 -> 匿名类 -> 表达式
- 表达式简化
- 去参数类型 注:多个参数,一去都去,且加()
- 去代码段 注:一个语句时,多条须加{}
- 去类名+方法名
1.7 操作线程:停止、休眠、礼让 ...
- stop() 注:一般使用标志位控制run中循环次数,不推荐使用JDK的stop方法
- sleep(int minseconds)、wait 等
- yeild() 注:正在执行的进程会回到就绪队列排队,但执行结果取决于CPU调度,即不一定礼让成功
- join() (线程插队,会造成其他线程阻塞)
- getState() (线程监测状态)
1.8 守护线程
线程分为用户线程和守护线程(如垃圾回收,后台记录操作,监控内存等),虚拟机不用维护守护进程。
Thread.setDaemon(default false) //默认false(用户进程),true(守护进程)
1.9 线程同步机制
每个对象都有一把锁(锁机制)
-
线程的不安全性
-
sleep 可以放大问题,使用线程 sleep 使并发的线程同时进行而避免CPU太快导致问题捕捉不到
-
synchronized 关键字的两种方式 同步方法、同步块(隐式锁)
优化:加方法锁会影响执行效率,代码分为只读代码和修改代码,故只需给修改代码加锁即可 同步块可以是给任意对象加锁的,而同步方法默认是给 this 对象加锁
synchronized(obj){...} //使用方法
- 死锁
死锁的产生原因:互相抱着双方想下一步获取的资源而又不松手
- 显式锁 - Lock
JDK 5.0 始,更强的线程同步机制,通过显式定义锁对象,实现了java.util.concurrent.locks.Lock接口,比较常用的是其实现类ReentrantLock(可重入锁)。
class demo{
ReentrantLock lock = new ReentrantLock();
try{
lock.lock();
...
}finally{
lock.unlock();
}
}
- JUC 并发安全类集合(拓展)
1.10 线程通信
synchronized只是实现了线程同步,而未实现不同线程间的通信。
- OBJ 对象的方法
- hashCode()、toString() ...
以下是只能在同步方法/代码块中使用(否则会抛出异常)的方法,用于解决线程通信的方法
- wait()、wait(long timeout)
- notify()、notifyAll()
- 生产者消费者问题
- 管程法与信号灯法(即信号量取反)
1.11 线程池
线程池相关API
- ExecutorService 线程池接口,有子类如ThreadPoolExecutor
- void execute(Runnable ommand): 执行任务/命令,无返回值,一般用来执行Runnable
- Future submit(Callabletask): 有返回值,一般用来执行Callable
- void shutdown(): 关闭线程池
- Executors 工具类、线程池的工厂类,用于创建并返回不同类型的线程池