Java 多线程创建和线程状态
一、进程和线程
多任务操作系统中,每个运行的任务是操作系统运行的独立程序。
为什么引进进程的概念?
为了使得程序能并发执行,并对并发执行的程序加以描述和控制。
因为通常的程序不能并发执行,为使程序(含数据)能独立运行,为它配置PCB——描述和和控制进程的的运行。
PCB记录了了操作系统所需的、用于描述进程的当前情况以及控制进程运行的全部信息。
PCB是使一个在多道程序环境下不能独立运行的程序,成为一个能独立运行的基本单位、一个能与其它进程并发执行的基本单位。
OS是根据PCB来对并发执行的进程进行控制和管理。
所谓创建进程,实际上是创建进程实体中的PCB;撤销进程,实质上是撤销进程的PCB。
程序:只是一组有序指令的集合,存放于某种介质上,本身是静态的。
进程实体:由程序段、相关数据段和PCB组成。是动态的,有生命周期。
进程的实质是进程实体的一次执行过程。
进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。
1、进程
进程是操作系统任务调度的单位,每个任务对应一个进程。
进程是操作系统的资源管理单位,进程包含代码和数据的地址空间以及其他的资源,比如打开的文件和信号量。不同的进程的地址空间是相互隔离的。
应用程序在启动后会创建一个进程,系统需要为进程分配ID号和内存。
2、线程介绍
线程是比进程更小的调度单位,它依附于进程存在,多线程是在一个进程内执行多段代码序列。
线程有自己的程序计数器、寄存器、栈等。
引入线程的动机在于操作系统中阻塞式I/O的存在,当一个线程所执行的I/O被阻塞的时候,同一进程中的其他线程可以使用处理器执行计算,从而提高程序的执行效率。
3、进程和线程比较
为什么不使用多进程?
进程的调度代价高,而多线程的调度代价小,更高效。
为什么线程间通信效率高?
进程中的多个线程共享进程的内存空间,当有新的线程产生时,操作系统不分配新的内存,而是让新线程共享原有进程块的内存。因此,线程间通信效率高。
4、JVM中的进程和线程
Java程序都运行在JVM中,每启动一个应用程序,就会启动一个JVM进程。在JVM环境中,所有的程序代码的执行都以线程实现。
Thread类提供多线程支持,应用可以创建多个并发执行的线程。
应用总是从main()方法开始运行,main()方法运行在一个线程内,称为主线程。
每个线程都有一个调用栈,一旦创建一个新的线程,就产生一个新的调用栈
5、应用中可以创建两类线程:用户线程和守护线程。
用户线程执行完毕时,JVM自动关闭当前程序。
守护线程独立于JVM,守护线程一般是由操作系统或者用户自己创建的,
二、创建线程
继承Thread类,实现Runnable接口和使用Timer类。
1、继承Thread类
Thread类实例只是一个对象,有变量和方法,创建于堆内存上,具有生命周期,可以与其他线程对象通信并协作完成特定任务。
线程动作放在Thread中的run()方法,它代表了线程需要完成的具体任务,因此,run()被称为线程体~
run()不是自动执行的,为了让run()执行必须调用Thread类的start()方法,调用start()方法的目的是创建新线程并执行该线程对象的run()方法,新线程与启动它的线程将并发执行。start()方法启动后立即返回,并不等待新建线程的执行,这意味着新建线程的run()方法在调用start()方法后不一定立即执行,需要等待JVM的调度。这种多线程之间的不确定性,是并发编程的难点所在。
public class InheritThread extends Thread {
private String name;
public InheritThread(String name){
this.name=name;
}
public void run(){
int c=0;
while(c<5){
System.out.println("Greetings from thread '"+name+"'!");
c++;
}
}
} class Main {
public static void main(String args[]) {
InheritThread greetingsA = new InheritThread("Inherited");
greetingsA.start();//创建新的线程
System.out.println("Thread has been started!"); }
}
2、实现Runnable接口
定义实现java.lang.Runnable接口的类,并实现该接口的run()方法,在run()中编写线程执行代码。
public class RunnableThread implements Runnable{
private String name;
public RunnableThread(String name){
this.name=name;
}
public void run(){
System.out.println("Greetings from runnable'"+name+";!");
}
} class Main {
public static void main(String args[]) {
/*创建线程,需要利用RunnableThread对象生成一个Tread类的对象,然后调用start()*/
RunnableThread greetingsB=new RunnableThread("runnable");
Thread greetingsThread=new Thread(greetingsB);
greetingsThread.start();
}
}
这种方式的好处是,任何对象都可以实现Runnable接口,从而不受Java单继承泛型的限制。run()方法能访问类中所有的变量和方法,包括私有变量和方法。这种方式的缺点是,违反了每个对象应该有一个单一的、明确的职责的原则
3、使用Timer类和TimerTask类
Timer是一种线程设施,用于安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行,可以看成一个定时器,可以调度TimerTask。
TimerTask是一个抽象类,实现了Runnable接口,所以具备了多线程的能力。
一个Timer可以调度任意多个TimerTask,它会将TimerTask存储在一个队列中,顺序调度,如果想两个TimerTask并发执行,则需要创建两个Timer。看一个简单的例子:
import java.util.Timer;
import java.util.TimerTask;
class PaintTask extends TimerTask{
public void run(){
System.out.println("update");
System.out.println("repaint");
}
} public class TimeDemo {
public static void main(String args[]){
Timer timer=new Timer();
timer.schedule(new PaintTask(),1000,1*1000); /*1秒后执行,周期为1秒*/
}
}
我们用其它方法实现同样的功能:
/*在线程的run()中执行循环,并休眠30ms,唤醒后调用更新和重绘*/
public class Animator extends Thread{
public void run(){
while(true){
try{
Thread.sleep(2000);
}
catch (InterruptedException e){
System.out.println("Thread is interrupted"+e.getMessage());
}
updateForNextFrame();
repaint();
}
}
private void repaint(){
System.out.println("repaint");
}
private void updateForNextFrame(){
System.out.println("update");
}
public static void main(String args[]){
Animator animator=new Animator();
animator.start();//会调用run方法
System.out.println("Thread has been started!");
}
}
三、线程状态的转换
1、JVM的线程调度
线程调度是指按照一定的策略为多个线程分配CPU的使用权。
分时调度:所有线程轮流获得CPU的使用权,并平均分配占用时间。
抢占式调度:根据线程的优先级别来获取CPU使用权,这也是JVM采用的策略。
2、线程的5种状态
新建(new)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、死亡(Dead)。
阻塞意味着等待,阻塞的线程不参与线程调度,自然不占用CPU。多线程环境下,非阻塞的线程才能被调度运行。
新线程在start()方法被调用后就进入就绪状态,随着JVM调度的程序状态的改变在运行和就绪之间切换。遇到阻塞进入阻塞状态,当run()方法结束或发生异常线程终止执行,进入死亡状态。
3、使线程离开当前运行状态的情况有三种:
(1) 线程的run()方法执行完毕;
(2) 在对象上调用wait()方法(不是在线程上调用);
(3) 线程试图调用对象的方法时不能在对象上获得锁
4、线程状态的转换
线程的调度程序是JVM的一部分,JVM可以决定将当前运行状态线程切换到就绪状态,以便让另一个线程获得运行机会,而不需要任何理由。对于处于就绪状态的线程,他们被选择执行的顺序是没有保障的。对于任何一组启动的线程来说,JVM不能保证其执行次序,持续时间也不能保证。
线程状态及转换:
5、关于线程的阻塞状态
阻塞状态是线程因为某种原因放弃了CPU使用权,暂时停止运行,直到线程进入就绪状态。
阻塞情况分为3种:
(1)等待阻塞:运行的线程执行了wait()方法,JVM把该线程放入等待池中。
(2)同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池。
(3)其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()方法状态超时、join()方法等待线程终止或超时、或者IO处理完毕时,线程重新转入就绪状态。
Java 多线程创建和线程状态的更多相关文章
- -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中
本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait( ...
- Java多线程系列--“JUC线程池”06之 Callable和Future
概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...
- Java多线程系列--“JUC线程池”02之 线程池原理(一)
概要 在上一章"Java多线程系列--“JUC线程池”01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析Th ...
- Java多线程系列--“JUC线程池”03之 线程池原理(二)
概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...
- Java多线程系列--“JUC线程池”04之 线程池原理(三)
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3509960.html 本章介绍线程池的生命周期.在"Java多线程系列--“基础篇”01之 基 ...
- Java多线程——进程和线程
Java多线程——进程和线程 摘要:本文主要解释在Java这门编程语言中,什么是进程,什么是线程,以及二者之间的关系. 部分内容来自以下博客: https://www.cnblogs.com/dolp ...
- Java多线程并发02——线程的生命周期与常用方法,你都掌握了吗
在上一章,为大家介绍了线程的一些基础知识,线程的创建与终止.本期将为各位带来线程的生命周期与常用方法.关注我的公众号「Java面典」了解更多 Java 相关知识点. 线程生命周期 一个线程不是被创建了 ...
- Java多线程系列--“JUC线程池”05之 线程池原理(四)
概要 本章介绍线程池的拒绝策略.内容包括:拒绝策略介绍拒绝策略对比和示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3512947.html 拒绝策略 ...
- 转:java多线程CountDownLatch及线程池ThreadPoolExecutor/ExecutorService使用示例
java多线程CountDownLatch及线程池ThreadPoolExecutor/ExecutorService使用示例 1.CountDownLatch:一个同步工具类,它允许一个或多个线程一 ...
随机推荐
- Java中基本数据类型
在数据类型中,最常用也是最基础的数据类型,被称作基本数据类型.可以使用这些类型的值来代表一些简单的状态. Java 语言的基本数据类型总共有以下8 种,下面是按照用途划分出的4 个类别: 定点类型: ...
- json常用的注解
json注解: 1.@JsonIgnoreProperties: 此注解是类注解,作用是json序列化时将java bean中的一些属性忽略掉,序列化和反序列化都受影响. 写法将此标签加在model ...
- js优先队列的定义和使用
//队列,先入先出,FIFO function Queue() { this.items = []; } Queue.prototype = { constructor: Queue, enqueue ...
- Nginx之进程间的通信机制(Nginx频道)
1. Nginx 频道 ngx_channel_t 频道是 Nginx master 进程与 worker 进程之间通信的常用工具,它是使用本机套接字实现的,即 socketpair 方法,它用于创建 ...
- iSCSI存储技术
iSCSI(Internet Small Computer System Interface),Internet小型计算机系统接口,又称为IP-SAN,是一种基于因特网及SCSI-3协议下的存储技术, ...
- Mac下持续集成-Mac下Tomcat+Jenkins集成环境搭建
一.MAC安装jdk及环境变量配置 1)访问Oracle官网 http://www.oracle.com,浏览到首页的底部菜单 ,然后按下图提示操作: 2)下载完成后点击安装包,按提示即可完成安装. ...
- matlab gui界面设计记录
我们要进行的程序是彩色图像处理试验示例,用这个程序来练习我们的gui前台设计. 程序功能介绍:具有彩色图像处理及保存和音乐播放功能效果如下图 2 在MATLAB的命令窗口中输入guide命令,打开gu ...
- 前端知识点回顾之重点篇——ES6的Iterator和Generator
Iterator 迭代器是一种接口.是一种机制. 为各种不同的数据结构提供统一的访问机制.任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员). Iter ...
- 人才-T型人才:百科
ylbtech-人才-T型人才:百科 T型人才是指按知识结构区分出来的一种新型人才类型.用字母“T”来表示他们的知识结构特点.“—”表示有广博的知识面,“|”表示知识的深度.两者的结合,既有较深的专业 ...
- Java:基础知识点
1. 面向对象的特征 (1)封装:把过程和数据包围起来,对数据的访问只能通过已定义的界面.即现实世界可以被描绘成一系列完全自治.封装的对象,这些对象通过一个受保护的接口访问其他对象:(2)继承:是一种 ...