学习新东西最好的方法是从源头上去下手,也就是第一个写这个的人。如果是看别人写的话,可能有些东西错过了,因为每个人的基础不一样,想法也不一样。同样的知识点被几个人消化过之后,你最好看到的兴许就是残渣。你没有享受这个消化的过程。
对于学习java来说,其实有一份资料是很有学习的重要性的。那就是Java Language Specification。
JVM支持一次执行多个线程。这些线程独立的执行保存在共享内存中的值和对象的代码。线程可能被含有多个硬件处理器支持,或者但处理器的时间切片,或者多硬件处理器的时间切片。
Java中线程用类Thread代表。用户创建线程的唯一的方法就是创建该类对象。每个线程都和这样的一个对象相关。当线程对象调用start()方法时,线程就启动了(就绪状态,等待cpu分配时间切片来执行,即调度).
线程的行为,尤其是当没有正确同步的话可能造成困惑和违反直觉的。
一、同步synchronization
Java编程语言提供了多种机制便于线程之间的通信。这些方法中最基本的就是同步,它是通过监听器(monitor)来实现的。Java中的每个对象都和一个监听器相关,这个监听器可以被线程加锁或者释放锁。同一时刻只能有一个线程可以持有该锁。任何其他尝试对监听器加锁的线程都会被阻塞知道他们可以对该监听器加锁。一个线程t可能多次对该监听器上锁,释放锁抵消一个加锁操作。
synchronized声明计算对一个对象的一个引用;它然后尝试对该对象的监视器执行锁动作,知道成功执行锁动作才执行后续代码。执行完后,或者正常或者唐突的释放该对象上的监听器,该操作(释放)是自动执行的。
同步方法调用的时候自动执行锁(lock)动作。方法体直到lock动作执行成功才执行。如果该方法是一个实例方法,它锁上的监听器是与它调用的实例对象相关(也就是this).如果该方法是static,也就是类方法。加锁的监听器就是Class对象
Java语言既不会阻止也不会需要检测死锁的条件。在程序中线程持有多个对象的锁应该使用传统的技术避免死锁,即创建高级别的锁优先级以防死锁。
其他的线程之间的通信机制,包括读和写volatile变量。使用java.util.concurrent包里面的类。
二、等待集和通知(wait set and notification)
每个对象除了有一个相关的监视器,还和一个等待集相关。等待集中存放的是线程。
当一个对象创建第一次创建的时候,它的等待集是空的。添加线程到等待集或者从等待集移除线程的操作都是原子性的。主要通过Object.wait方法,Object.notify和Object.notifyAll.对等待集的操作也可以被线程的中断状态影响,而且通过Thread类中的方法处理中断。此外,the Threadclass's methods for sleeping and joining other threads have properties derived from those of wait and notification actions.
(1)Wait
等待操作通过调用wait方法(),或者带有时间的等待。
线程从wait中正常返回如果没有抛出InterruptedException.
假设线程t表示在对象object m上实行wait方法,n表示t在m上锁动作的个数不包含释放锁。可能导致如下结果:
1.如果n为0(表示线程t还没有拥有对象m的锁),导致抛出IllegalMonitorStateException.
2.如果调用的是wait(long millisecs,int nanosecs)方法。第二个参数的范围不是在0-999999.或者第一个参数为负。将会抛出IllegalArgumentException.
3.如果线程t被中断。将抛出InterruptedException而且t的中断状态设为false。
要不然,发生以下的
1.线程t添加到对象m的等待集,执行n次锁释放。
2.线程t直到它从m的等待集移除才执行进一步的指令。可以通过如下方法执行从等待集移除。
一、m调用notify方法
二、m调用notifyAll方法
三、t调用interrupt方法。
3.线程t对m执行n次加锁操作。
4.如果线程t通过步骤2的interrupt方法移除等待集,那么t的中断状态被设为false并且wait方法抛出InterruptedException。
(2)Notification
调用方法notify和notifyAll.
假设线程t表示在对象object m上实行wait方法,n表示t在m上锁动作的个数不包含释放锁。可能导致如下结果:
1.如果n为0,然后IllegalMonitorStateException抛出。
这种情况下线程t还没有拥有对象m的锁。
2.n>0,调用notify方法。如果m的等待集不为空。线程u是m当前等待集中被选中并且从等待集中移除。不能保证等待集中的哪个线程被选中。
3.n>0,调用notifyAll方法。m等待集中的所有线程被移除。
注意,only one of them at a time will lock the monitor of m。
(3)Interruptions
调用thread方法Thread.interrupt。
假设线程t中调用线程u.interrupt方法,对于一些线程u,t和u可能一样。那么该操作导致线程u的中断状态变为true;
此外,如果存在一些对象m,他们的等待集包含线程u,那么线程u从m的等待集移除。使得u从等待操作中恢复。重获m的锁。抛出中断异常。
Thread.isInterrupted方法可以判断线程的中断状态。静态方法Thread.interrupted用来观察和清除它自己的中断状态。