文章目录
- 一,概念运行程序会创建一个进程但OS调度的最小单元是线程(轻量级进程)普通的程序包含的线程:
- 二,启动线程和退出线程
-
- 1,创建线程的方法
- 2,启动线程
- 3、线程中断
-
- interrupt方法
- 中断线程的两种写法
-
- try/catch块中包含while循环
- 处理不可中断的阻塞
- 三、线程的状态
- 四、常用方法深入理解
-
-
- 1、run()
- 2、start()
- 3、sleep()
- 4、yield()
- 5、wait()
- 6、notify()
- 7、notiyfAll()
-
一,概念运行程序会创建一个进程但OS调度的最小单元是线程(轻量级进程)普通的程序包含的线程:
- 监听Ctrl-Break // 监听中断信号
- 附加监听器// 获取内存转储,线程转储
- 信号调度程序// 将信号分给jvm的线程
- 终结者// 调用对象的终结者方法
- 参考处理程序// 清除参考
- 主// 程序的主入口
可以用以下代码打印出以上线程:
讯享网
从上面可知:即使我们运行一个什么都不做的主方法,也会有以上6个线程,另外关于垃圾回收的GC线程,如果程序一直不用启动垃圾回收机制,那么GC线程是不会启动的。
为什么要用多线程
1.充分利用多处理核心;
2.更快的响应时间(用户订单的场景,发送邮件等部分可由其他线程执行)
二,启动线程和退出线程
1,创建线程的方法
方法一,将类声明为Thread的子类。该子类应重写Thread类的运行方法。接下来可以分配并启动该子类的实例。
讯享网
然后,下列代码会创建并启动一个线程: PrimeThread p = new PrimeThread(143); p.start();
方法二,声明实现Runnable接口的类。该类然后实现run方法。然后可以分配该类的实例,在创建Thread时作为一个参数来传递并启动。
然后,下列代码会创建并启动一个线程:
讯享网
每个线程都有一个标识名,多个线程可以同名。如果线程创建时没有指定标识名,就会为其生成一个新名称。
方法三:通过线程池创建
例如:
方法四:通过Future Callable 和FutureTask
FutureTask实现RunnableFuture接口,而RunnableFuture继承自Runnable, Future,所以可以把FutureTask传给Thread创建线程,本质上还是方法二。


FutureTask继承了Future,可以获取线程的执行结果,所以还可以改成如下:
2,启动线程
调用线程的start()方法即可启动线程。
线程完成:
- run()方法执行完成;
- 抛出一个未处理的异常导致线程的提前结束
补充:不要在构造函数启动线程,有发生因为指令重排导致对象逸出的风险,详情自行百度,这里不细说。
3、线程中断
interrupt方法
不安全的取消:
单独使用一个取消标志位.Stop(),suspend(),resume()是过期的api,很大的副作用,容易导致死锁或者数据不一致。
使用线程的中断 :
interrupt() 中断线程,本质是将线程内部的中断标志位设为true,其他线程向需要中断的线程打个招呼。是否真正进行中断由线程自己决定。
isInterrupted() java单线程基础 线程检查自己的中断标志位。
静态方法Thread.interrupted() 将中断标志位复位为false。
如果我们不使用线程内部的中断标志位,而是自己起一个变量用于标志中断,那么遇到wait()、sleep()等方法时,我们的标志位就不起作用了,这是不靠谱的做法,如:
运行结果:
线程一直停留在wait()方法,没有终止。
由上面的中断机制可知Java里是没有抢占式任务,只有协作式任务。当线程处于阻塞(如调用了java的sleep,wait等等方法时)的时候,是不会理会我们自己设置的取消标志位的,但是这些阻塞方法都会检查线程的中断标志位。一旦查到中断标志位是中断状态时,立刻中断线程,并对sleep,wait等方法有效。
下面介绍两种中断线程的写法
中断线程的两种写法
先上代码:
try/catch块中包含while循环
在TryWhileWhenBlock的cancel方法中设置线程标志变量 并调用了interrupt()方法,将线程设置为中断
,设置中断之后,会停止wait方法并抛出InterruptedException异常,并且抛出异常后,中断标志位会改成false,抛出异常已经退出while循环,程序结束。
运行结果如下:

把main方法改成如下:
在WhileTryWhenBlock的cancel方法中调用了interrupt()方法,将线程的中断标志位设为true,设置中断之后,会停止wait方法并抛出InterruptedException异常,并且抛出异常后,中断标志位会改成false,我们在异常处理的代码块中调用 重新设置中断位为true,重新回到while条件,不满足条件,结束循环。
运行结果如下:


处理不可中断的阻塞
如何让我们的代码既可以响应普通的中断,又可以关闭底层的套接字呢?
覆盖线程的interrupt方法,在处理套接字异常时,再用super.interrupt()自行中断线程。
示例代码:
三、线程的状态
新建(NEW): 线程被创建,但是没有调用start方法。
可运行(RUNNABLE): 可运行线程的线程状态,由cpu决定是不是正在运行,有人把正在运行的线程再细分为运行状态(running)。
被阻塞(BLOCKING): 受阻塞并且正在等待监视器锁的某一线程的线程状态。
等待(WAITING ): 某一等待线程的线程状态。
计时等待(TIMED_WAITING): 具有指定等待时间的某一等待线程的线程状态。
被终止(TERMINATED ): 已终止线程的线程状态。

四、常用方法深入理解
1、run()
run就是一个普通的方法,跟其他类的实例方法没有任何区别,只是线程启动后会调用到该方法。
2、start()
启动线程调用的方法,然后Java 虚拟机调用该线程的 run 方法。
结果是两个线程并发地运行;当前线程(从调用返回给 start 方法)和另一个线程(执行其 run 方法)。
3、sleep()
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。该线程不丢失任何监视器的所属权。
输出结果:
其中输出 之后停了4秒,再输出下面的内容。这是因为ThreadSleep线程里面把sleep方法放到同步代码块里面了,sleep期间其他线程不能获得同一对象锁,如果把sleep方法放到同步代码块外面,那么对其他线程的影响就会小得多。
4、yield()
当前线程出让cpu占有权,当前线程变成了可运行状态,下一时刻仍然可能被cpu选中,不会释放锁。
5、wait()
调用以前,当前线程必须要持有锁,调用wait方法后,当前线程会处于等待状态,加入对象锁的等待集合中,同时,线程会释放当前持有的锁,其他线程可以在这时获取该锁,其他线程获取到该锁后,wait的线程会进入blocked状态,直到被notify() 方法或 notifyAll() 方法唤醒。
java.lang.Object#wait(long)方法表示等待某一时间内是否有线程对其唤醒,如果超时则自动唤醒。
注意1: 虽然会wait自动解锁,但是对顺序有要求, 如果在notify被调用之后,才开始wait方法 的调用,线程会永远处于WAITING状态。
注意2: 这些方法只能由同一对象锁的持有者线程调用,也就是写在同步块里面,否则会抛出 IllegalMonitorStateException异常。
注意3: 从wait方法返回前即被notify、notifyAll唤醒后,线程必须重新去获取监视器锁,成功获取锁后才能执行。
关于避免假唤醒的问题参考这篇文章:并发编程之 wait()为什么要处于while循环中?
6、notify()
唤醒在此对象监视器上等待的单个线程,如果改对象有多个线程在等待,那么唤醒哪一个完全由cpu决定(谨慎使用)
此方法必须在同步方法或同步块即synchronized上下文中被调用,即当前线程持有监视器锁。
执行方法后,当前线程不会立即释放当前拥有的监视器锁,必须等待此方法的方法或同步块即synchronized上下文执行完,退出同步,当前线程才会释放锁,此时wait状态的线程才可以去竞争获取监视器锁。
7、notiyfAll()
唤醒在此对象监视器上等待的所有线程。(推荐使用)
相关原理:在Java语言中,每个对象都有一个与之关联的监视器,它实际上是对象头(Object Header)中的一部分。当一个线程调用了某个对象的wait方法后,该线程会释放对象的锁并进入等待状态,并将自己加入到该对象的等待队列中。当其他线程调用了该对象的notify方法后,JVM会从等待队列中选择一个线程将其唤醒。
下面是关于wait和notifyAll的实例:
运行结果
注意:
1、wait、notify、notifyAll只能在synchronized关键字中使用,且调用wait、notify、notifyAll的对象与锁对象相同,否则会抛出IllegalMonitorStateException异常。
2、wait() 方法调用后,会破坏原子性。
补充: 调用完notify或者notifyAll后,线程并不会马上从阻塞中退出,抢到锁后才会继续执行。
输出结果(相同的输出结果只保留两条,多于的用。。。表示):
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/4435.html