Java的多线程基础(一)
2017-10-27 00:00
267 查看
摘要: Java ,多线程
在本篇blog中,主要讨论Java多线程的基础部分,旨在简单的学习Java中多线程部分的入门知识,为接下来的学习线程的执行过程的分析、线程中方法(wait、sleep、join、yield等)的理解、线程中高级类的使用做铺垫。
使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为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关键字,首先就要明确monitor的概念,Java中的每个对象都有一个监视器,来监测并发代码的重入。在非多线程编码时该监视器不发挥作用,反之如果在synchronized 范围内,监视器发挥作用。
java.lang.Object的wait/notify方法,表示等待/通知,它们的前提是已经获得了锁,在wait(等待)期间会释放锁。在wait方法的注释里明确提到:线程要调用wait方法,必须先获得该对象的锁,在调用wait之后,当前线程释放该对象锁并进入休眠,只有以下几种情况下会被唤醒:其他线程调用了该对象的notify或notifyAll、当前线程被中断、调用wait时指定的时间已到。
第一种创建线程的方式是直接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
在本篇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
相关文章推荐
- java基础巩固笔记(5)-多线程之线程并发库
- JAVA多线程和并发基础面试问答
- Java基础之多线程
- 黑马程序员——java基础日记——多线程(1)
- Java多线程基础学习
- java线程基础巩固---多线程死锁分析,案例介绍
- 学习笔记7—Java基础5_多线程
- Java基础知识-多线程
- Java基础之多线程2
- 黑马程序员--Java基础之多线程
- JAVA多线程和并发基础面试问答
- java速度入五._多线程编程基础
- java基础学习——多线程
- 【Java基础】Java多线程之线程组和线程池
- java多线程基础
- Java基础--多线程--练习(过隧道)
- 浅析Java多线程程序设计机制-Java基础-Java-编程开发
- Java_基础—多线程(同步代码块和同步方法)
- java 多线程基础(一)
- Java基础——多线程