并发
(By wind5shy:http://blog.csdn.net/wind5shy)
Thread
n start():初始化线程,使线程开始执行,Java虚拟机调用该线程的run()。
n yield():线程暂停,回到可执行状态,锁保留,让出CPU时间,但只让给同优先级的线程,所以如果某线程使用yield()后如果没有相同优先级的线程则该线程又会再次被执行。
n sleep():线程暂停,回到可执行状态,锁保留,让出CPU时间,可使不同优先级的线程获得执行的机会。
n join():等待该线程执行完毕。
n setPriority():设置线程优先级。JDK有10个优先级,但操作系统的优先级各不相同,所以无法做到完美的映射,可行的策略是只使用MIN_PRIORITY、NORM_PRIORITY和MAX_PRIORITY三个优先级。
n setDaemon():将该线程标记为守护线程或用户线程(后台线程),当正在运行的线程都是守护线程时,Java 虚拟机退出(即程序立即结束,如书上的例子)。后台线程创建的任何线程都会自动被设置为后台线程。
n interrupt():中断线程。
n interrupted():测试当前线程是否已经中断并清除线程的中断标识。换句话说,如果连续两次调用该方法,则第二次调用必定返回 false。异常捕获时也将清除线程的中断标识,所以异常被捕获时这个标识总是为false。
n isInterrupted():测试线程是否已经中断,线程的中断状态不受该方法的影响。
n run():继承Thread或实现Runnable的一般目的就是改写run(),将要并发执行的代码需要写在里面。如果在子类中新建其他方法,如run1(),写在里面的代码是不能并发执行的。
synchronized关键字
被synchronized修饰的代码为同步代码,只有获得对象锁(又称监视器)的线程才能访问这些代码,直到访问完成释放锁其他线程才能访问,但类中非synchronized的代码其他线程什么时候都可以访问。synchronized static锁的是class对象,所以相当于给整个类上锁。synchronized关键字不是方法签名(private、static是)的一部分,所以在继承和重载的时候还是要同步的话需要手动加上。
一个例子:
synchronized f();
synchronized g();
h();
如果某线程正在执行f(),则其他线程不能执行同一对象的g(),但可以执行h()。
原子操作
对除long和double以外的基本类型进行简单的赋值或返回值操作是原子操作,long和double加上valitale关键字后相应操作也是原子操作。但如果把这些操作写在方法里方法就不是该方法就不一定是原子操作了,比如int i = 1;这单个语句是原子操作没有问题(否则多线程下面的同步就没法控制了)但void setI { int i = 1;}就很可能不是原子操作了。
临界区/同步块:synchronized(object){//some code},线程在进入some code(临界区)之前必须获得object的锁(而不是包含这段代码的对象的锁)
Object的线程控制
n wait():暂停线程并释放当前对象的锁。 T将其自身放置在对象的等待集中,然后放弃此对象上的所有同步要求。在发生以下四种情况之一前,T被禁用,且处于休眠状态:
1. 其他某个线程调用此对象的notify(),并且线T被任选为被唤醒的线程。
2. 其他某个线程调用此对象的notifyAll()。
3. 其他某个线程中断T。
4. 大约已经到达指定的实际时间。但是,如果timeout为零,则不考虑实际时间,在获得通知前T将一直等待。
然后,从对象的等待集中删除线程T,重新进行线程调度。然后,该线程以常规方式与其他线程竞争,以获得在该对象上同步的权利;一旦获得对该对象的控制权,该对象上的所有其同步声明都将被恢复到以前的状态,这就是调用wait()时的情况。然后,T从wait()的调用中返回。所以,从wait()返回时,该对象和T的同步状态与调用wait()时的情况完全相同。
n notify()/notifyAll():唤醒当前对象监视器(对象锁)上等待的单个/所有线程。(如果所有线程都在当前对象上等待,则会选择唤醒其中一个线程。)选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个wait(),在对象的监视器上等待。 直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在当前对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定当前对象的下一个线程方面没有可靠的特权或劣势。(这是Sun JDK1.6 API中的解释,所以书中说线程在notify()之后就进入就绪状态是不完全正确。当然,实际情况中很可能只有notify()后的线程在等待对象锁,就可以马上获得锁而进入就绪状态。可以参考下面的线程状态图。)
上面三个方法都只能作为拥有当前对象的锁的线程来调用,即只能在同步方法或同步块里使用。
线程状态图:
n lock pool:等待锁定池(我个人的叫法,正规的叫法不太清楚),包含被notify()唤醒的线程及其他等待锁定对象线程;在当前线程执行完释放对象锁之后,这些线程通过竞争选取一个线程获得对象锁。
n sleep pool:休眠池(个人的叫法,Sun JDK1.6 API叫做对象的等待集),包含正在休眠的线程。
死锁
必须同时满足的四个条件:
1、 互斥:有资源不能被共享。
2、 占有与请求:进程占有资源同时等待其他进程占有的资源。
3、 不剥夺:进程占有的资源不能被强行剥夺。
4、 循环等待:若干进程之间形成一种头尾相接的循环等待资源关系。
所以解除死锁只需打破其中一个条件即可。
(By wind5shy:http://blog.csdn.net/wind5shy)
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/wind5shy/archive/2010/03/04/5346490.aspx