黑马程序员技术交流社区

标题: Java多线程总结 [打印本页]

作者: kebi    时间: 2015-11-10 21:20
标题: Java多线程总结
本帖最后由 kebi 于 2015-11-10 21:33 编辑

Java多线程是什么
Java提供的并发(同时、独立)处理多个任务的机制。多个线程共存于同一JVM进程里面,所以共用相同的内存空间,较之多进程,多线程之间的通信更轻量级。依我的理解,Java多线程完全就是为了提高CPU的利用率。Java的线程有4种状态,新建(New)、运行(Runnable)、阻塞(Blocked)、结束(Dead),关键就在于阻塞(Blocked),阻塞意味着等待,阻塞的的线程不参与线程分派器(Thread Scheduler)的时间片分配,自然也就不会使用到CPU。多线程环境下,那些非阻塞(Blocked)的线程会运行并充分利用CPU。

Java线程阻塞(Blocked)的类型:

Java多线程的创建
[size=13.3333px]线程驱动任务的处理,涉及到两个概念,线程(Thread)、以及任务(Task, Java里面叫Runnable),推荐的做法是写一个类(class)实现Runnable接口,作为Task,传给Thread的的构造函数,调用 Thread的start方法即可。当然你也可以直接继承Thread类,重写(Override)run方法。从任务抽象的角度来说,推荐前者,后者的 优势是简单。想创建多个线程,就new多个Thread并start即可。不过JVM有一个最大线程数的限制,-Xssjava命令行非标准可选项可以设 置大小,不同平台可能不一样,需要查文档或写代码验证。

Java多线程的资源竞争(race condition)
[size=13.3333px]多个线程同时访问同一份资源(内存块)的时候,可能发生某一个线程处理到一半,被别的线程抢走资源并修改的问题,造成资源的不一致。要避免此类问题,唯一的解决方案就是加锁
[size=13.3333px]Java有两种锁可供选择:

原子性和可见性
Java多线程之间的合作
[size=13.3333px]Java多线程共享相同的内存,自然可以通过访问和修改同一份资源(对象)来交互和通信,只是需要注意线程的安全性。此外,Java还提供一些其它的线程交互方式,绝大多数都通过线程分派器(Thread Scheduler)完成。主要的一些交互方式如下:

yield
[size=13.3333px]提示线程分派器(Thread Scheduler)当前线程已经完成一个完整的工作,此时是一个切换到其它线程的好时机。通常这可以提高切换的可能,但是需要注意切换只是可能,不是一定发生。所以业务不能完全依赖于yield。Thread.yield()。

join
[size=13.3333px]暂停当前线程的运行,等待另外一个线程运行完毕之后再继续运行。anotherThread.join()。这种依赖关 系可以得到保证。依个人的理解,此时当前线程也是被阻塞(Blocked)了,等待另外一个线程运行完毕,然后唤醒。join会抛出 InterruptedException(间接证明当前线程被Blocked),当前线程调用interrupt方法会解除依赖,并抛出 InterruptedException。

wait notify notifyAll
[size=13.3333px]这三个都是Object的方法,wait用来阻塞(Block)当前线程,但是会释放对象的锁,notify告 诉线程分派器唤醒等待的某一个线程,notifyAll会唤醒所有等待的线程。需要特别注意的是,这三个方法都需要在锁定的环境 (synchronized)里面使用,否则编译通过,但是运行报错。wait notify notifyAll 与 synchronized配对使用。
  1. while(conditionIsNotSatisfied)
  2.     wait()
复制代码


await signal signalAll
[size=13.3333px]await signal signalAll是java.util.concurrent.locks.Condition的三个方法,Condition可以通过Lock获得Condition condition = lock.newCondition()。从功能上来说,await signal signalAll与wait notify notifyAll应该是相同的,只是await signal signalAll与Condition配对使用。
  1. while(conditionIsNotSatisfied)
  2.     condition.await()
复制代码


取消线程的运行
[size=13.3333px]推荐的做法是调用线程的interrupt方法。线程也有stop函数,不过JDK1.5以后被弃用了,原因据说是因为会引起死锁。所有会抛出InterruptedException的线程阻塞都可以调用interrupt方法唤醒,不过是通过异常的方式退出,如果需要释放资源,一定要使用try finally语句。 IO的阻塞、synchronized阻塞、lock阻塞都无法使用interrupt方法唤醒。IO阻塞可以通过关闭(close)资源的方式退出。如 果是非阻塞的线程,需要检测interrupt状态,有两个方法,isInterrupted和interrupted,interrupted有副作 用,会清理状态。标准的能够响应interrupt的程序格式大概如下:
[size=13.3333px]
  1. public void run() {
  2.         try {
  3.             // check interrupt status
  4.             while (!Thread.interrupted()) {
  5.                 // declare resource
  6.                 try {
  7.                     // use resource
  8.                 } catch (Exception e) {
  9.                     // release resource
  10.                 }
  11.             }
  12.         } catch (InterruptedException ex) {
  13.             // do something when InterruptedException triggered.
  14.         }
  15.     }
复制代码







欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2