1,实现Runnable接口的类(new Thread(subRunnalbe)),在同时new该类的多个实例时,是同一实例(Runnable实例)的多个线程。而继承Thread类的线程,每次new的都是新的thread实例。
2, start()方法最本质的功能是从CPU中申请另一个线程空间来执行 run()方法中的代码,它和当前的线程是两条线,在相对独立的线程空间运行,调用start()方法后,run()方法的代码会和当前线程并发(单CPU)或并行 (多CPU)执行。
3, 对象调用interrupt()方法,它对应的线程并没有被中断,只是改变了它的中断状态。只有当线程执行到sleep,wait,join等方法时,或者自己检查中断状态而抛出异常的情况下,线程才会抛出异常。
4,interrupted()方法是一个static方法,就是说只能在当前线程上调用,是说中断的状态已经结束(到非中断状态了),不仅检查当前线程 是否为中断状态,而且在保证当 前线程回来非中断状态
5,isInterrupted()方法则仅仅检查线 程对象对应的线程是否是中断状态,并不改变它的状态。
6,sleep()方法中是类方法,也就是对当前线程而言的。
7,join()方法,正如第一节所言,在一个线程对象上调用join方法,是当前线程等待这个线程对象对应的线程结束,比如有两个工作,工作A要耗时10秒钟,工作B要耗时10秒或更多。我们在程序中先生成一个线程去做工作B,然后做工作A。
new?B().start();//做工作B
A();//做工作A
工作A完成后,下面要等待工作B的结果来进行处理.如果工作B还没有完成我就不能进行下面的工作C,所以
B?b?=?new?B();
b.start();//做工作B
A();//做工作A
b.join();//等工作B完成。
C();//继续工作C。
8,yield()方法也是类方法,只在当前线程上调用,理由同上,它主是让当前线程放弃本次分配到的时间片。
9, [wait(),notify()/notityAll()方法是普通对象的方法(Object超类中实现),而不是线程对象的方法] [wait(),notify()/notityAll()方法只能在同步方法中调用]
10,[synchornized关键字],作用:把一个单元声明为synchornized,就可以让在同一时间只有一个线程操作该方法
对于同步块,synchornized获取的是参数中的对象锁: synchornized( obj ){ //....... } 线程执行到这里时,首先要获取obj这个实例的锁,如果没有获取到线程只能等待.如果多个线程执行到这里,只能有一个线程获取 obj的锁,然后执行{}中的语句,所以,obj对象的作用范围不同,控制程序不同。
public void test(){
Object o = new Object();
synchornized(obj){
//...............
}
}
这段程序控制不了任何,多个线程之间执行到Object o = new Object();时会各自产生一个对象然后获取这个对象有监视锁,各自皆大欢喜地执行.
而如果是类的属性:
class Test{
Object o = new Object();
public void test(){
synchornized(o){
//...............
}
}
}
所有执行到Test实例的synchornized(o)的线程,只有一个线程可以获取到监视锁.
有时我们会这样:
public void test(){
synchornized(this){
//...............
}
}
那么所有执行Test实例的线程只能有一个线程执行.而synchornized(o)和synchornized(this)的范围是不同 的,因为执行到Test实例的synchornized(o)的线程等待时,其它线程可以执行Test实例的synchornized(o1)部分,但多 个线程同时只有一个可以执行Test实例的synchornized(this).]
而对于
synchornized(Test.class){
//...............
}
这样的同步块而言,所有调用Test多个实例的线程赐教只能有一个线程可以执行.
11,[synchornized方法]
如果一个方法声明为synchornized的,则等同于把在为个方法上调用synchornized(this).
如果一个静态方法被声明为synchornized,则等同于把在为个方法上调用synchornized(类.class)
12,wait方法和notify/notifyAll方法.这两个(或叫三个)方法都是Object对象的方法,而不是线程对象的方法.如同锁一样,它们是在线程中调用某一对象上执行的. class Test{ public synchornized void test(){ //获取条件,int x 要求大于100;
if(x < 100)
wait();
}
}
这里为了说明方法没有加在try{}catch(){}中,如果没有明确在哪个对象上调用wait()方法,则为this.wait();
假如:
Test t = new Test();
现在有两个线程都执行到t.test();方法.其中线程A获取了t的对象锁,进入test()方法内.
这时x小于100,所以线程A进入等待.
当一个线程调用了wait方法后,这个线程就进入了这个对象的休息室(waitset),这是一个虚拟的对象,但JVM中一定存在这样的一个数据结构用来记录当前对象中有哪些程线程在等待.
当一个线程进入等待时,它就会释放锁,让其它线程来获取这个锁.
所以线程B有机会获得了线程A释放的锁,进入test()方法,如果这时x还是小于100,线程B也进入了t的休息室.
这两个线程只能等待其它线程调用notity[All]来唤醒.
但是如果调用的是有参数的wait(time)方法,则线程A,B都会在休息室中等待这个时间后自动唤醒.
13,[为什么真正的应用都是用while(条件)而不用if(条件)]
在实际的编程中我们看到大量的例子都是用?
while(x < 100)
wait();go();而不是用if,为什么呢?
在多个线程同时执行时,if(x <100)是不安全的.因为如果线程A和线程B都在t的休息室中等待,这时另一个线程使x==100了,并调用notifyAll方法,线程A继续 执行下面的go().而它执行完成后,x有可能又小于100,比如下面的程序中调用了--x,这时切换到线程B,线程B没有继续判断,直接执行go(); 就产生一个错误的条件,只有while才能保证线程B又继续检查一次.
14,[notify/notifyAll方法]
这两个方法都是把某个对象上休息区内的线程唤醒,notify只能唤醒一个,但究竟是哪一个不能确定,而notifyAll则唤醒这个对象上的休息室中所有的线程.
一般有为了安全性,我们在绝对多数时候应该使用notifiAll(),除非你明确知道只唤醒其中的一个线程.
那么是否是只要调用一个对象的wait()方法,当前线程就进入了这个对象的休息室呢?事实中,要调用一个对象的wait()方法,只有当前线程获取了这个对象的锁,换句话说一定要在这个对象的同步方法或以这个对象为参数的同步块中.
class MyThread extends Thread{
Test t = new Test();
public void run(){
t.test();
System.out.println("Thread say:Hello,World!");
}
}
public class Test {
int x = 0;
public void test(){
if(x==0)
try{
wait();
}catch(Exception e){}
}
public static void main(String[] args) throws Exception{
new MyThread().start();
}
}
这个线程就不会进入t的wait方法而直接打印出Thread say:Hello,World!.
而如果改成:
public class Test {
int x = 0;
public synchornized void test(){
if(x==0)
try{
wait();
}catch(Exception e){}
}
public static void main(String[] args) throws Exception{
new MyThread().start();
}
}
我们就可以看到线程一直等待,注意这个线程进入等待后没有其它线程唤醒,除非强行退出JVM环境,否则它一直等待.
所以请记住:
[线程要想调用一个对象的wait()方法就要先获得该对象的监视锁,而一旦调用wait()后又立即释放该锁]
转自:http://blog.csdn.net/zuoluoboy/article/details/4034935 转载地址:http://blog.zol.com.cn/860/article_859847.html
来源:oschina
链接:https://my.oschina.net/u/726257/blog/337035