1。在java中线程不是孤立的
2.并发可以提高处理事务的效率即在一段时间内可以处理或者完成更多的事情;并行是一种更为严格,更为理想的并发
3.线程的创建与启动
在java中,创建一个线程就是创建有个Thread(或者其子类)类的对象
4.调用线程的start()方法来启动,启动线程的实质就是请求JVM运行相应的线程这个线程具体什么时候运行是通过线程调度器(Scheduler)决定的
5.start()方法调用结束后,并不意味着子线程开始运行;新开启的线程会执行run方法
6.如果开启的多个线程,start()调用的顺序并不一定就是线程启动的顺序
7.多线程运行结果与代码执行顺序或者调用顺序无关;多线程运行结果是随机的
8.线程中的常用方法
cruuentThread():获取当前线程。java中的任何一段代码都是执行在某个线程当中的,执行当前线程的代码就是当前线程;同一段代码可能被不同的线程执行,因此当前线程是相对的
Thread.setName()和Thread.getName():设置线程名称和获取线程名称
isAlive():判断当前线程是否处于活动状态。活动状态:线程已启动并且尚未终止
sleep():让当前线程休眠指定的毫秒数
getId():获取线程的唯一标识。注意:当某个编号的线程运行结束后,该编号可能被后续创建的线程使用;重启JVM后,同一个线程的编号可能不一样
yield():Thread.yield()作用是放弃当前的CPU资源
setPriority():设置线程的优先级
interrupt():可以中断线程,注意调用interrupt()方法仅仅只是在当前线程打一个停止标志,并不是真正的停止线程
setDaemon():
9.java线程的优先级是1-10,如果超出这个范围会抛出异常IllegalArgumentException;线程优先级本质上就是给线程调度器一个提示信息以便于调度器决定先调用哪个线程,注意:不能保证优先级高的线程一定先运行;java优先级设置不当会导致某些线程永远无法执行,即产生的线程饥饿,线程的优先级并不是设置的越高越好
10.java中的线程分为用户线程和守护线程,守护线程是为其他线程提供服务的线程,如垃圾回收器就是一个典型的 守护线程。守护线程是不能单独运行的,当JVM中没有其他用户线程,只有守护线程时JVM会推出,守护线程会自动销毁
11.线程的生命周期(重点)
线程的生命周期就是一个线程从创建到销毁的整个过程
线程的生命周期可以通过getState()获得,线程的状态是通过Thread.State枚举类型来定义的,有以下几种状态:
NEW:新建状态,创建了线程对象,在调用start()启动之前的状态
RUNNABLE:可运行状态。它是一个复合状态,包含READY(表示该线程可以被线程调度器进行调度使他处于RUNNING状态)和RUNNING(表示该线程正在执行)。Thread.yield()可以把线程有RUNNING状态转换为READY状态
BLOCKED:阻塞状态线程发起一个阻塞的IO操作或者申请有其他线程独占资源,线程会转换为BLOCKED阻塞状态。处于阻塞状态的线程不会占用CPU。当阻塞IO操作执行完或者线程获得了其申请的资源。线程可以转换为RUNNABLE状态
WAITING:等待状态。线程执行了object.wait()或者Thread.join()方法会把线程转换为WAITING等待状态,执行object.notify()或者加入的线程执行完毕,当前线程会转换为RUNNABLE状态
TIMED_WAITING状态与WAITING状态类似都是等待状态出别在于处于该状态的线程不会无限的等待,如果线程没有在指定的时间内完成期望的操作,该线程自动转换为RUNNABLE
TERMINATED:终止状态,线程结束处于终止状态
12.多线程的优势与存在的风险
优势:可以提高系统的吞吐率,多线程可以是一个进行有多个并发的操作;提高响应速度,web服务器会采用一些专门的线程负责用户的请求,缩短了用户的等待时间;充分的利用了多核处理器资源。通过多线程可以充分利用CPU
风险:线程安全问题多线程共享数据时,如果没有采取正确的并发访问控制措施,就可能会产生数据一致性问题 ;线程活性问题,由于程序自身的缺陷或者由资源稀缺性导致线程一直处于非RINNABLE状态
常见的活性故障:死锁问题(鹬蚌相争);锁死(睡美人,王子死了);活锁(猫咬尾巴);饥饿
上下文切换。处理器从执行一个线程切换到执行另一个线程
可靠性。可能由一个线程导致JVM意外终止,其他线程也无法执行
13.线程安全问题
非线程安全主要是指多个线程对同一个对象的实例变量进行操作,会出现值被更改,值不同步的情况
线程的安全性问题表现为三个方面:原子性、可见性、有序性 。
原子性:原子就是不可分割的意思。原子不可分割有两层含义一个是访问(读写)某个共享变量的操作从其他线程来看,该线程要么执行完毕,要么尚未发生,即其他线程看不到当前操作的中间结果;另一个访问同一组共享变量的原子操作是不能交叉的
java中有两种方式实现原子性:一种是使用锁;另一个是利用处理器的CAS指令。锁具有排他性,保证共享变量在某一个时刻只能被一个线程访问;CAS指令直接在硬件层次上实现
可见性:在多线程环境下,一个线程对某个共享变量进行修改后,后续其他线程可能无法立即读到更新的结果,这就是线程安全问题的另一种形式可见性
有序性:有序性是指在什么情况下一个处理器上运行的线程所执行的访问内存的操作在另外一个处理器运行的其他线程看来是乱序的。乱序是指内存访问操作顺序看起来发生了变化。在多核处理器的环境下,编写的顺序结构,这种操作执行的顺序可能是没有保障的
14.重排序:在一个处理器上执行的多个操作,在其他处理器来看他的顺序与目标代码指定的顺序可能不一样,这种现象称为重排序
重排序是对内存访问有序操作的一种优化,可以在不影响单线程程序正确的情况下提升程序的性能,但是可能多多线程程序的正确性产生影响,即可能导致线程安全问题
重排序和可见性类似,不是必然出现的
15.与内存操作顺序有关的几个概念:
源代码顺序:就是源码中指定的内存访问顺序
程序顺序:处理器上运行的目标代码所指定的内存访问顺序
执行顺序:内存访问操作在处理器上的实际执行顺序
感知顺序:给定处理器所感知到的该处理器及其他处理器的内存访问操作顺序
16重排序可分为指令重排序和存储子系统重排序两种
执行重排序:主要是由JIT编译器和处理器引起的,指程序顺序和执行顺序不一致
存储子系统重排序:是有告高速缓存、写缓存器引起的。感知顺序与执行顺序不一致
17.如何保证内存访问的顺序性
可以使用volatile关键字,也可以使用synchronized实现有序性
18.java内存模型
19.线程同步性机制:线程同步机制是一套协调线程之间的数据访问的机制。该机制可以保障线程安全
20.java平台提供的线程同步机制包括:锁,volatile关键字,final关键字,static关键字,以及相关的API,如:Object.wait()等
21锁概述
线程安全问题产生的前提是多个线程并发访问共享数据
将多个线程对共享数据的并发访问变为串行访问,即一个共享数据一次之能被一个线程访问,锁九世纪利用这种机制来保障线程安全的
锁可以理解为对共享数据保护的一个许可证。对于同一个许可证保护的共享变量来说,任何线程像哟啊访问这些共享数据必须先持有该许可证,一个线程只有在持有许可证的情况下才可以对线程进行访问;并且一个许可证只能被一个线程持有;许可证线程在结束对共享数据访问后把必须释放其持有的许可证
锁具有排他性,即一个锁一次只能被一个线程持有。这种锁被称为排他锁或互斥锁
JVM把锁分为内部所和显示锁。内部所通过synchronize关键字实现;显示锁通过java.concurrent.locks.Lock接口的实现类实现
22.锁的作用:锁可以实现对共享数据的安全访问。保障线程的原子性、可见性、有序性。锁是通过互斥保证原子性的;可见性保障是通过写线程冲刷处理器的缓存和读线程刷新处理器缓存这两个动作实现的。在java平台中,锁的获取隐藏着刷新处理器缓存的动作锁的释放隐藏着冲刷处理器缓存的动作;锁能够保障有序性,写线程在临界区所执行的在读线程 临界区看来像是完全按照源码顺序执行的
注意:通过使用锁保障线程的安全性不许满足一下条件
a.这些线程在访问数据时必须使用同一个锁,即使时读数据的线程也需要同步锁
23.锁相关的概念
可重入性描述这样的一个问题:一个线程持有该锁的情况下能否再次申请该锁如果一个线程持有一个锁 的时候还能继续申请该锁,则该锁时可重入的,否则称该锁是不可重入的
锁的争用与调度:java平台内部锁属于非公平锁,显示锁Lock既支持公平锁又支持非公平锁
锁的粒度:一个锁可以保护的共享数据数量的大小称为锁的粒度。锁保护的数据量大,称该锁的粒度粗否则就称该锁的粒度小。锁的粒度过粗会导致线程在申请锁时进行不必要的等待,锁的粒度过细会增加锁调度的开销
24.内部锁(synchronized关键字)
java中的每一个对象都有一个与之关联的内部锁,这种锁也被称为监视器,这种内部锁是排他锁,可以保障原子性、可见性、有序性
内部锁是通过synchronized关键字实现的。该关键字可修饰代码块、方法
25线程出现异常会自动释放锁