Java线程概述及API1

Java线程概述及API一

1 创建线程与创建线程运行时代码

在Java中,创建线程的方式只有一种,就是创建Thread对象的实例。创建线程运行时代码有三种方式:

第一种:继承Thread类,覆写其run方法。

第二种:实现Runnable接口,实现run方法,Thread类也实现了Runable接口。

第三种:实现Callable接口,实现其call方法,这种方式是在JDK1.5中的java并发包中引入的。

 

start()方法与run()方法的区别

start()方法用于启动线程,start方法调用之后,线程进入可运行状态,一旦线程调度程序调度执行,线程即进入运行状态,线程启动后JVM才会给线程分配相应的资源,例如栈内存空间。然后回调线程运行时代码。

run()方法用于执行线程的运行时代码,如果直接调用该方法并没有创建新的线程而是在当前线程中被执行。

 
覆盖了Thread对象的run方法,同时传入一个Runnable的实现类?

我们知道线程创建完成之后,然后JVM回调线程运行时代码run(),所以查看Thread的默认run()实现:

 

/* What will be run. */
private Runnable target;
....
@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

 

 其中target就是Runable对象,默认的run方法的逻辑是,如果传递了Runnable的实现类,就运行Runnable的run方法。故:当覆盖了Thread对象的run方法之后,执行的肯定是覆盖之后的逻辑,原来的这段逻辑如果不存在了,

就算传入了Runnable的实现类,也不会执行。

 

最后,Thread对象实现了Runnable接口(实现了run方法),而构造方法中又可以接受一个Runnable接口的实现类(也实现了run方法),称之为target,在执行的时候,如果target存在,就执行target的run方法。这实际上是装饰者设计模式(又称包装设计模式)

 

sleep()方法与wait()方法的区别

sleep()方法是Thread类中定义的方法,可以在任意地方调用,作用是让线程进行休眠暂停执行,在休眠期间线程不会请求CPU执行,因此其他线程(甚至更低优先级的线程)可以获得更多的运行机会。但是如果持有同步锁,并不会释放锁

sleep方法有InterruptedException编译时异常需要捕获。它是静态方法,所以不能指定休眠某一特定的线程t.sleep()它只会是使当前线程被sleep 而不是t线程。sleep方法调用之后,线程进入到阻塞状态不释放所占有的资源,sleep方法结束返回之后,线程重新回到可运行状态,而不是运行状态,需要线程调度机制重新恢复其到运行状态。

 

wait()方法是Object类中定义的方法,只能在同步方法或者同步代码块中调用,如果持有同步锁,会释放锁,让其他需要获得该锁的线程有机会运行。当线程调用wait()方法后会进入等待队列(进入这个状态会释放所占有的所有资源,与阻塞状态不同)

wait方法同样也可以在wait期间因为被其他对象调用interrupt()方法二产生InterruptedException运行时异常。一旦一个对象调用了wait方法,必须要采用notify()和notifyAll()方法唤醒该进程。调用wait或者notify的时候,当前线程必须要是对象lock的拥有者,否则会抛出IllegalMonitorStateException异常。

synchronized (share) {
   share.wait();
}

 当线程在synchronized中调用了share.wait()时,在放弃了CPU的同时,也放弃了share这个对象的lock,进入这个对象的wait pool。

当另外一个线程调用了share.notify()时,将从wait pool中拿出一个线程,让该线程获得lock,并进入可运行状态,等待线程调度执行。

这也就是为什么wait/notify需要加锁的原因。