JAVA多线程

线程的4个状态:

创建(new),就绪(runnable),阻塞(blocked),终止(dead)

Runnable接口:

定义了一个描述任务的方式,他具有任何内在的线程能力,使用它必须将它显示的依附在线程上。

传统的方法是将其传递给一个Thread的构造方法。

Thread对象:

当主线程创建Thread对象后,并没有创建其对象的引用,在start()之后每个Thread都会注册自己,并创建自己一个单独的执行线程,在其执行完run()方法并死亡前是无法回收该对象的。

Exector:

线程池可以为我们管理Thread对象,相当于在客户端与执行任务之间的一个间接层。

ExcetorService由Excetor的静态方法创建。

newCachedThreadpool()会在程序中创建与任务数相同的线程, 然后在回收旧线程时才会停止创建新线程。当所需要的线程的数量过多影响到性能时应选用newFixedThreadpool();

newFixedThreadpool()可以指定线程数量的上限。

newSingleThreadExector()数量为1的FixedThreadpool,所有任务以队列的形式一个个顺序运行。

shutdown()方法防止其他任务提交给该Excetor.


Callable接口与Future:

是带有返回值的Runnable接口,内部声明的方法是call().一般情况下配合ExctoeService使用。Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果。Future由ExecutorService.sumbit返回。

Future提供了三种功能:

1)判断任务是否完成;

2)能够中断任务;

3)能够获取任务执行结果。

因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此有FutureTask。

FutureTask:

publicclassFutureTaskimplementsRunnableFuture

FutureTask类实现了RunnableFuture接口,我们看一下RunnableFuture接口的实现:

publicinterfaceRunnableFutureextendsRunnable, Future {

voidrun();

}

可以看出RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

FutureTask提供了2个构造器:

publicFutureTask(Callable callable) {

}

publicFutureTask(Runnable runnable, V result) {

}

事实上,FutureTask是Future接口的一个唯一实现类。


后台线程:

调用setDaemon方法可以将线程设置成后台线程,但是必须在线程start后才能起作用。当程序终止时就会杀死全部后台线程。后台线程派生出的子线程全部默认为后台线程。


线程中捕获异常:

线程中产生的异常不能够在主线程捕获。如果需要在主线程捕获子线程产生的异常需要用到uncanughtException.

uncanughtException是一个接口。实现该接口,并调用Thread.setUncanughtExceptionHandle(..),就可以在指定的线程中捕获其他线程产生的异常。


synchronized与Lock的区别:

ReentrantLock是Lock的一个实现,他允许尝试获得锁但最终未获得锁,因为可以决定离开去做别事情。而synchronized则会等待锁。因此ReentrantLock赋予了更细粒度的控制力。


原子性:

一个操作是原子性去取决于其底层的实现,因此是与操作系统有关,应避免使用原子性来替代线程同步。


线程的终止:

当线程被阻塞时(如调用了wait/sleep等方法时),可以使用 Thread.interrupt()方法打断阻塞的状态,当调用此方法后 Thread的 interrupted 标记被设置为 true. 此时如果你调用 interrupted()方法来测试中断状态(此方法会清空中断状态,也可以使用isInterrupted()来测试中断状态,这时中断状态不会被清空).

当调用 interrupte()方法时会抛出 InterruptedException,这时中断状态被清空.

线程被 sleep/wait 阻塞时可以被 interrupt,但如果线程被 IO或synchronized 阻塞则不可以被 interrupt,

线程间的协作:

我们上面讲的主要是如何让线程互斥的访问一个共享的资源,现在要研究如何让线程间进行协作,也就说二个线程有个先后,必须第一个线程完成后,第二个线程才能开始执行(像生产者与消费者)。

要完成上面所说的就要用到 Object.wait()/notify()/notifyAll()了.

wait/notify/notifyAll 的调用都必须在获得这个对象的 monitor 时.

当wait 被调用时,当前线程被加入 wait set,这时这个线程不再被系统调度,直到有其它线程调用特定对象的notify或notifyAll方法时,此线程从wait set 中移除,开始被系统调度,但它必须再次获得特定对象的monitor才能继续。当获得对象的monitor后,wait方法会返回,这时此线程会恢复到调用wait方法前的状态.

注意: 当调用 wait()时会释放对象锁,而 sleep/yield 等方法不会释放锁.

wait/notify/notifyAll 及 synchronized 都是相对于一个对象来说的,都需要这个对象的锁.

你可能感兴趣的:(JAVA多线程)