回顾
* 进程:一段正在运行的程序,资源分配的基本单位
* 线程:进程中的任务,cpu调度的最小单元
* 线程的创建:
* 1)Thread 继承
* 2)Runnable 实现
* 3)Callable 实现
* 4)匿名内部类
* 启动线程:start (run call)
*
* 守护线程
* 守护线程是一类比较特殊的线程,一般用于处理后台的工作,比如JDK的垃圾回收线程
* 什么守护线程?为什么会有守护线程?何时需要守护线程?
* 明确:JVM什么情况下退出?
* The java virtual machine exits when the only thread running are
* all dameon thread.
* 如果JVM没有一个守护线程,JVM进程不会退出
* 守护线程具备自动结束生命周期的特点,非守护线程不具备这样的特点
* eg. 如果垃圾回收线程是一个非守护线程,那么某一程序完成工作运行结束,JVM无法退出,
* 垃圾回收线程依旧工作
*
* 例:使用匿名线程的方式创建一个线程,这个线程持续睡眠1ms,主线程睡眠1000ms输出
* 主线程main结束
*
* 注意:setDaemon方法只能线程启动之前使用,如果对于一个线程已经死亡或者未
* 启动,那么设置setDaemon会抛出IllegalThreadStateException
*
* 并发与并行概念
* 并发指的是多个线程操作同一个资源,不是同时执行,而是交替执行,单核cpu,只不过
* cpu时间片很短,执行速度很快,看起来同时执行
*
* 并行才是真正的同时执行,多核cpu。每一个线程使用一个单独的cpu运行
*
* QPS: 每秒能够响应的请求数
* 吞吐量: 单位时间内能够处理的请求数
* 平均响应时间: 系统对某一个请求的平均响应时间 QPS = 并发数/平均响应时间
* 并发用户数: 系统可以承载的最大用户数
*
* 互联网系统结构如何提高系统的并发能力?
* 垂直方向
* 水平方向(集群(多个做同一件事) 分布式(一个复杂的事情拆分去做))
*/
public class TestDemo3 {
public static void main(String[] args) {
//匿名线程
Thread thread = new Thread(){
@Override
public void run() {
while(true){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
//设置thread为守护线程
thread.setDaemon(true);
thread.start();
/**
* thread是一个非守护线程,main线程正常运行结束之后,JVM进程并没有退出;
* 如果我们将thread设置为守护线程,main线程结束生命周期,JVM进程退出
*
*/
//睡眠 Thread.sleep(1000)
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//sout
//main线程结束
System.out.println("main thread finished");
}
}
线程生命周期
* new(新建状态) new关键字创建一个线程对象,它并不是处于一个执行状态,因为还没有start
* 启动线程
* Runnable(就绪状态) 线程对象调用start方法,才是在JVM中真正创建了一个线程,线程一经启动
* 并不会立即执行,该状态的所有线程位于就绪线程池中,等待操作系统的资源,如:处理器,获得
* cpu的使用权
* Blocked(阻塞状态) 等待一个监视器锁进入同步代码块或者同步方法,代码块/方法某一时刻只能够
* 有一个线程执行,其他线程只能等待
* Waiting(等待状态) Object.wait()/Thread.join()/LockSupport.park()都会使得线程阻塞,
* 从Runnable转换到Waiting状态
* Timed_Waiting(睡眠状态) 调用加超时参数的Object.wait(long mills)/Thread.slepp(long mills)/LockSupport.
* parkNano()/LockSupport.parkUntil()
* Terminated(终止状态) 是一个线程的最终状态,线程进入到Terminated状态,意味着该线程的生命周期结束了,下面这些情况都会使得线程进入Terminated状态
* 1)线程执行正常结束
* 2)线程运行出错意外结束
* 3)JVM crash
将这些场景比作一次跑步比赛
* 线程中常用方法
* 1)start()
* 启动一个线程,将线程添加一个线程组中,线程状态会从New状态转换到Runnable状态,然后获取
* Cpu之后进入Running状态执行run
* 2)sleep()
* sleep是一个静态方法,其中存在两个重载函数
* public static native void sleep(long millis)
* public static void sleep(long millis, int nanos)
* 使得线程进入睡眠状态,暂停执行,sleep不会放弃monitor lock的所有权
* jdk1.5之后,jdk引入一个枚举TimeUnit,其对sleep方法做了封装,直接使用从而时间单位
* 换算的步骤,比如线程睡眠3h27min8sec88msec
* 3)yield()
* yield表示提醒cpu调度器我愿意放弃当前的cpu资源,(属于启发式方法),如果cpu资源不紧张
* 的情况下,会忽略这种提示
* 面试题:yield和sleep的区别
* a.jdk1.5之前,yield调用了sleep
* b.sleep使得当前线程暂停执行,不会占用cpu资源
* yield只是对于cpu调度器的一个提示
* c.sleep会导致线程短暂的阻塞,yield会使得线程Runnable-》Runnable
* d.sleep会捕获到中断异常,yield不会捕获到中断异常
*
* 4)join()
* 含义:在线程B中join某个线程A,会使得B线程进入等待,直到线程A结束生命周期,或者达到给定的时间,
* 在这期间线程B会处于等待状态
* 课堂练习:
* ThreadA打印1-10, ThreadB打印打印1-10,,ThreadC打印1-10, 保证按照A->B->C顺序打印
* 5)wait()
* 6)notify()
* 7)notifyAll()
* 8)线程中断方法
A,B,C三个线程 使得A,B,C三个线程顺序打印1~10
join方法的应用:
class ThreadDemo extends Thread{
private Thread thread;
private String name;
public ThreadDemo(Thread thread, String name){
this.name = name;
this.thread = thread;
}
@Override
public void run() {
if(thread != null){
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(int i=1; i<=10; i++){
System.out.println(name +"::" +i);
}
}
}
public class TestDemo4 {
public static void main(String[] args) {
//A,B,C三个线程 使得A,B,C三个线程顺序打印1~10
ThreadDemo A = new ThreadDemo(null, "线程A");
ThreadDemo B = new ThreadDemo(A, "线程B");
ThreadDemo C = new ThreadDemo(B, "线程C");
A.start();
B.start();
C.start();
}
}
TimeUnit使用
new Thread(()->{
try {
//Thread.sleep(5000);
TimeUnit.HOURS.sleep(3);
TimeUnit.MINUTES.sleep(27);
TimeUnit.SECONDS.sleep(8);
TimeUnit.MILLISECONDS.sleep(88);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
线程方法
* wait 调用某个对象的wait()方法可以让当前线程阻塞
* notify 调用当前对象notify/notifyAll才能够唤醒这个对象所在的线程
* notifyAll
* 注意:使用这三个方法需要让当前线程拥有当前对象的monitor lock
*
* 线程中断方法
* 每个Java线程都会有一个中断状态位,程序可以检测这个中断状态位判读线程是否执行结束
*
* a.interrupt()
* public void interrupt() 由线程对象调用,将中断位置置为true
*
* 如下方法能够使得当前线程进入阻塞状态,调用interrupt方法可以打断阻塞,因此这种
* 方法被称之为可中断方法
* Object.wait()/wait(long)
* Thread.sleep(long)/TimUnit.XXX.sleep(long)
* Thread.join()/Thread.join(long)
*
* interrupt
* 如果一个线程被interrupt,设置interrupt flag;如果当前线程正在执行可中断方法,调用
* interrupt方法,反而导致interrupt flag被清除
*
* b.isInterrupted判断当前线程的中断状态位是否为true
*
* c.interrupted
* public static Boolean interrupted() 静态方法
* 调用interrupted会擦除中断状态位的标识
*/
这是wait和notify的应用
new Thread("A"){
@Override
public void run() {
synchronized (strs){
//同步代码块
try {
strs.wait(); //释放当前对象的monitor lock -》Waiting
//表示让当前线程进入到阻塞状态
System.out.println("the currend thread name is "+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
new Thread("B"){
@Override
public void run() {
synchronized (strs){
//strs.notify();//随机唤醒其中一个
strs.notifyAll(); //唤醒所有线程 然后所有线程开始抢锁
}
}
}.start();
这是interrupt的应用
public class TestDemo5 {
public static void main(String[] args) {
Thread thread = new Thread(){
@Override
public void run() {
while(true){
System.out.println(Thread.interrupted());
}
}
};
thread.setDaemon(true);
thread.start();
try {
TimeUnit.MILLISECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
public class TestDemo5 {
public static void main(String[] args) {
Thread thread = new Thread(){
@Override
public void run() {
while(true){
try {
TimeUnit.MILLISECONDS.sleep(1); //sleep会擦除中断状态位
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread.start();
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread is interrupted: "+thread.isInterrupted());
thread.interrupt();
System.out.println("Thread is interrupted: "+thread.isInterrupted());
Thread thread = new Thread(){
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(10); //使得子线程进入阻塞状态
//interrupt方法会打断这种阻塞,会抛出异常
} catch (InterruptedException e) {
System.out.println("I am be interrupted");
}
}
};
thread.start();
try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
thread.interrupt();
Thread thread = new Thread(){
@Override
public void run() {
while(true){
System.out.println("test interrupt");
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
//e.printStackTrace();
System.out.println(Thread.currentThread().isInterrupted());
}
}
}
};
thread.start();
thread.interrupt(); //将thread的中断状态位置为true
System.out.println("Thread interrupt flag: "+thread.isInterrupted());
sleep 可中断方法能够清除原本线程置为true的中断状态位
String strs = new String("test wait");