2 Java线程

一、线程简介

现代操作系统在运行一个程序时,会为其创建一个进程,在一个进程里可以创建至少一个或多个线程。
各个线程既可以共享进程资源(内存、文件I/O),又可以独立调度。

线程优先级

线程优先级决定线程分配多或者少处理器时间片资源。优先级从1-10,默认5,10为最高优先级。有些操作系统会忽略优先级,如Mac。

Daemon线程

任何线程都可以被设置成守护线程或用户线程。Daemon线程是一种支持型线程,是为其它线程服务的,主要被用作程序中后台调度及支持性工作。如GC守护、服务守护、编译守护、Finalizer守护
当一个虚拟机中只有Daemon线程时,虚拟机将会退出。但是在Java虚拟机退出时Daemon线程中的finally块并不一定会执行。
不能依靠Daemon线程的finally块来关闭或清理资源。

线程池创建多少线程

视多线程的具体应用场景而定,原则是将硬件的性能发挥到极致,主要是I/O设备和CPU。
I/O密集型计算:程序一般都是CPU计算和I/O操作交叉执行的,由于大部分情况下I/O操作执行的时间相对于CPU计算来说都很长,故佳线程数是与CPU计算和I/O操作的耗时比相关的。最佳线程数量=CPU核数*[1+(I/O耗时 / CPU耗时)]。
CPU密集型计算:大部分场景下都是纯CPU计算。理论上最佳线程数量=CPU核数,工程上一般设置为CPU核数+1。预防某个线程因某些原因阻塞。

二、线程状态

在这里插入图片描述
Java线程共6种状态:
1、新建状态(New):线程对象被创建后,还没有调用start()。
2、运行状态(Runnable):
就绪状态(Ready):可执行状态,线程对象被创建后,其它线程调用了该对象的start()方法。线程只能从就绪状态进入到运行状态,处于就绪状态的线程,随时可能被CPU调度执行。
运行(Running) : 线程获取到CPU时间片进行执行。
3、阻塞状态(Blocked): 放弃CPU使用权,暂时停止运行,等待获取监视器锁。只有一种场景会触发BLOCKED状态,就是在进入synchronized关键字修饰的方法或代码块(获取锁)时等待隐式锁。
4、等待状态(WAITING):等待其它线程做出一些特定动作(通知或中断)
5、超时等待状态(TIME_WAITING):可以在指定的时间自行返回
6、终止状态(Terminated) : 线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

三、启动和中止线程

启动一个线程前,最好为这个线程设置线程名称,在jstack分析时可以提供一些信息。

中断

中断可以理解为线程的一个标识位属性,它表示一个运行中的线程是否被其他线程进行 了中断操作。interrupt()方法仅仅是通知线程,线程有机会执行一些后续操作,同时也可以无视这个通知。中断适合用来取消或停止任务,是一种简便的线程间交互方式。
许多声明抛出InterruptedException的方法(例如Thread.sleep(long millis)方法)这些方法在抛出InterruptedException之前,Java虚拟机会先将该线程的中断标识位 清除,然后抛InterruptedException,此时调用isInterrupted()方法将会返回false。

boolean变量标识

程序手动添加一个boolean判断变量,来控制是否需要停止任务并终止该线程。

这种通过标识位或者中断操作的方式能够使线程在终止时有机会去清理资源,而不是武断地 将线程停止,因此这种终止线程的做法显得更加安全和优雅。

四、线程通信

1、等待/通知机制(wait/notify、await/signal)

在功能层面解耦,一个线程修改了一个对象的值,另一个线程感知到了变化,然后进行相应的操作,完成了等待方和通知方之间的交互。
wait()会释放锁,进入WAITING状态,进入等待队列。
notify()随机唤醒一个等待队列的线程,将等待队列中的一个线程移动到同步队列中。
等待/通知机制依托于同步(synchronized)机制,确保等待线程从wait()方法返回时感知到通知线程对变量做出的修改。
另外在while循环内使用wait():线程首先获取互斥锁,当线程要求的条件不满足时,wait()释放互斥锁,进入等待状态;当要求的条件满足时,通知等待的线程,重新获取互斥锁。
在这里插入图片描述

2、join

thread1.join()/thread1.join(time),即当前线程等待thread1线程终止,或最多等待某些时间。
join内部使用wait来实现等待,当线程终止时,会调用thread1线程自身的notifyAll()方法,会通知所有等待在thread1对象上的线程。join方法锁的是thread1线程实例。

3、volitale和synchronized关键字

volatile保证了所有线程对变量访问的可见性。在读取时读到的是主内存的值,在写入时直接刷新回主内存。
synchronized确保同一时刻只有一个线程处于方法或者同步块中,保证了线程对变量访问的可见性和排他性。
对同步块的实现通过monitorenter、monitorexit指令,同步方法则依靠方法修饰符上的ACC_SYNCHRONIZED修饰符实现。它们的本质都是对一个对象的监视器monitor进行排他性获取,同一时刻只能有一个线程获取到monitor。
没有获取到monitor的线程,则进入同步队列SynchronizedQueue,被阻塞在同步块和同步方法的入口处,线程变成BLOCKED状态。

4、ThreadLocal

线程安全的变量,通过set方法来设置一个值,在当前线程下再通过get方法获取到该线程设置的值。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值