1:线程
(1)线程也叫轻量级进程。它拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。
(2)一个java程序的运行不仅仅是main()方法的运行,而是main线程和多个其他线程的同时运行。
(3)如果要设置线程的优先级,那么需要注意:针对频繁阻塞(休眠或者I/O操作)的线程需要设置较高的优先级;而偏重计算(需要较多CPU时间或者偏运算)的线程则设置较低的优先级,确保处理器不会被独占。
(4)注意:线程优先级不能作为程序正确性的依赖,因为操作系统可以完全不用理会java线程对于优先级的设定。
博客:jstack工具使用?http://blog.csdn.net/fenglibing/article/details/6411999
(5)java线程的运行生命周期,在给定的某一个时刻,线程只能处于一个状态。
下面是JAVA线程状态变迁图:
说明:
NEW状态—一个被创建的线程,但是还没有调用start方法。
BLOCKED状态—一个线程因为等待临界区的锁被阻塞产生的状态。(Lock或者synchronize关键字产生的状态。)
WAITING状态—一个线程进入了锁,但是需要等待其他线程执行某些操作,时间不确定。(当wait,join,park方法调用时,进入waiting状态,前提是这个线程已经拥有锁啦。)
TIMED_WAITTING状态—一个线程进入了锁,但是需要等待其他线程执行某些操作,时间确定。(通过sleep或者wait timeout方法进入的限期等待的状态。)
TERMINATED状态—退出
注意容易混淆的概念:阻塞在JUC包中LOCK接口的线程状态却是等待状态,因为JUC包中LOCK接口对于阻塞的实现均使用了LockSupport类中的相关方法。
(5)Daemon线程,当java虚拟机中不存在非Daemon线程的时候,java虚拟机将会退出。
注意1:Daemon属性需要在启动线程之前设置,不能在启动线程之后设置。
注意2:在构建Daemon线程时,不能依靠finally块中的内容来确保执行关闭或清理资源的逻辑。
2:启动和终止线程
(1)线程的构建记住一句话:一个新构造的线程对象是由其parent线程来进行空间分配的,而child线程继承了parent是否为Daemon、优先级和加载资源的contextClassLoader以及可继承的ThreadLocal,同时还会分配一个唯一的ID来标识这个child线程。至此,一个能够运行的线程对象就初始化好啦,在堆内存中等待着运行。
(2)中断?简单的说:中断好比其他线程对该线程打了招呼,其他线程通过调用该线程的interrupt()方法对其进行中断操作。
(3)废弃的API:suspend()暂停、resume()恢复、stop()停止,为啥废弃呢?因为持有锁,不释放,可能导致死锁。致命的的是也不支持中断。
(4)如何安全的终止线程呢?一种方法:使用中断来取消或停止任务。另一种方法:利用一个boolean变量来控制是否需要停止任务并终止该线程。
3:线程间通信
(1)一个线程一旦开始运行,就拥有自己的栈空间。
(2)volatile可以用来修饰字段(成员变量),就是告知程序任何对该变量的访问均需要从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性。
(3)sychronized实现原理:对一个对象的监视器(monitor)进行获取,而这个获取过程是排他的。也就是同一时刻只能有一个线程获取到由synchronized所保护对象的监视器。
对象、对象监视器、同步队列和执行线程之间的关系
任意线程对Object(Object由synchronized保护)的访问,首先要获得Object的监视器。如果获取失败,线程进入同步队列,线程状态变为BLOCKED。当访问Object的前驱(获得了锁的线程)释放了锁,则该释放操作唤醒阻塞在同步队列中的线程,使其尝试对监视器的获取。
(3)等待/通知机制是任意java对象都具备的,因为定义在Object里面。下面是等待/通知相关方法:
使用wait()、notify()、notifyAll()时需要注意的细节:
1)使用wait()、notify()、notifyAll()时需要先调用对象加锁。
2)调用wait()方法后,线程状态由RUNNING变为WAITING,并将当前线程放置到等待队列中。
3)notify()或notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()或notifyAll()的线程释放锁之后,等待线程才有机会从wait()返回。
4)notify()方法将等待队列中的一个等待线程从等待队列中移到同步队列中,而notifyAll()方法则是将等待队列中所有的线程全部移到同步队列,被移动的线程状态由WAITING变为BLOCKED。
5)从wait()方法返回的前期是或得了调用对象的锁。
(4)等待/通知的经典范式,分别针对等待方(消费者)和通知方(生产者)
等待方遵循如下原则:
a:获取对象的锁
b:如果条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件。
c:条件满足则执行对应逻辑。
通知方遵循如下原则:
a:获得对象的锁。
b:改变条件
c:通知所有等待在对象上的线程。
(5)管道输入/输出流和普通文件的输入/输出流或者网络输入/输出流不同处:它主要用于线程之间的数据传输,而传输的媒介为内存。
PipedOutputStream、PipedInputStream面向字节
PipedWriter、PipedReader面向字符
(6)Thread.join():如果一个线程A执行了thread.join()语句,表示:当前线程A等待thread线程终止后才从thread.join()返回。这里涉及了等待/通知机制(等待前驱线程结束,接收前驱线程结束通知)
(7)ThreadLocal(线程变量)的使用。它是一个以ThreadLocal对象为键、任意对象为值的存储结构。这个结构会被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。
4:线程应用实例
(1)等待超时模式?(使用等待超时模式来构造一个简单的数据库连接池。)
(2)线程池技术?(使用线程池技术构建一个简单的web服务器。)
网友评论