您的位置:首页 > 编程语言 > Java开发

Java的多线程基础(一)

2017-10-27 00:00 267 查看
摘要: Java ,多线程

在本篇blog中,主要讨论Java多线程的基础部分,旨在简单的学习Java中多线程部分的入门知识,为接下来的学习线程的执行过程的分析、线程中方法(wait、sleep、join、yield等)的理解、线程中高级类的使用做铺垫。

一、为什么使用多线程

使用多线程的理由之一是和进程相比,它是一种非常花销小,切换快,更"节俭"的多任务操作方式。在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。

使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。

除了以上所说的优点外,和进程比较,多线程程序作为一种多任务、并发的工作方式,有以下的优点:

提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。

使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。

改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。

二、线程的状态与生命周期

请看图:



有图可知,线程的状态有一下几个:

1、新建状态(New):新创建了一个线程对象。

2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。

3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。

4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:

等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)

同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。

其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(注意,sleep是不会释放持有的锁)

5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

三、每个对象都有的方法(synchronized, wait, notify)

synchronized, wait, notify 是任何对象都具有的同步工具。

说到synchronized关键字,首先就要明确monitor的概念,Java中的每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用,反之如果在synchronized 范围内,监视器发挥作用。

java.lang.Object的wait/notify方法,表示等待/通知,它们的前提是已经获得了锁,在wait(等待)期间会释放锁。在wait方法的注释里明确提到:线程要调用wait方法,必须先获得该对象的锁,在调用wait之后,当前线程释放该对象锁并进入休眠,只有以下几种情况下会被唤醒:其他线程调用了该对象的notify或notifyAll、当前线程被中断、调用wait时指定的时间已到。

四、java中基本线程类

基本线程类指的是Thread类,Runnable接口,Callable接口。那么如何创建线程呢?

第一种创建线程的方式是直接extends Thread 覆盖run()方法即可。代码如下:

  


  ------------------------------------------------------------------------------------------------

  


这种实现的方式的缺点是,一个java类智能extends 继承一个父类,有的时候不免有点尴尬。

第二种实现的方式是实现Runnable接口,实现run()方法。

  


  ------------------------------------------------------------------------------------------------

  


第三种方式是 implements Callable,实现call()方法可以得到线程的执行结果。



------------------------------------------------------------------------------------------------



本篇blog主要参考的blog有:

http://www.cnblogs.com/vanl/p/4970284.html

http://www.cnblogs.com/wxd0108/p/5479442.html

http://www.cnblogs.com/GarfieldEr007/p/5746362.html

http://www.cnblogs.com/gguozhenqian/archive/2011/11/16/2251521.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息