Java的多线程基础(一)

本文介绍了Java多线程的基础知识,包括多线程的优势、线程的状态与生命周期、对象的同步方法以及Java中的基本线程类。适合初学者了解多线程的基本概念。

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

一、为什么使用多线程

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

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

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

  1. 提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。
  2. 使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
  3. 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。 

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

    请看图:

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

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

转载于:https://my.oschina.net/u/3471006/blog/1557430

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值