线程的创建和运行
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程的创建和运行相关的知识,希望对你有一定的参考价值。
C语言可以访问内存地址,Java里不可以访问内存地址
JAVA里面只支持单继承
线程是一个程序内部的顺序控制流
线程和进程的区别:
进程是指运行中的应用程序,每一个进程都有自己独立的内存空间。对一个应用程序可以同时启动多个进程。例如每次执行JDK的java.exe程序,就启动了一个独立的Java虚拟机进程,该进程的任务是解析并执行Java程序代码
线程是指进程中的一个执行流程,有时也称为执行情景。一个进程可以由多个线程组成,即在一个进程中可以同时运行多个不同的线程,它们分别执行不同的任务。当进程内的多个线程同时运行,这种运行方式称为并发运行。
程序、进程与多任务
程序(program)是对数据描述与操作的代码的集合,是应用程序执行的脚本。
进程(process)是程序的一次执行过程,是系统运行程序的基本单位。程序是静态的,进程是动态的。系统运行一个程序即是一个进程从创建、运行到消亡的过程。
多任务(multi task)在一个系统中可以同时运行多个程序,即有多个独立运行的任务,每个任务对应一个进程。
多进程优点:各个进程独立,互不影响
缺点:各个进程独立造成交流困难,进程交流涉及到进程的通信,比较麻烦
JAVA里面不支持多进程,只支持多线程。
多线程优点:多线信息传递快
减轻编写交互频繁、涉及面多的程序的困难(如监听网络端口)。
程序的吞吐量会得到改善(同时监听多种设备,如网络端口、串口、并口以及其他外设)。
有多个处理器的系统,可以并发运行不同的线程(否则,任何时刻只有一个线程在运行)。
多线程缺点:每个线程公用一块数据,所以有锁的控制,这也是比较麻烦的。
每个线程都是通过某个特定Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体。
使用start()方法,线程进入Runnable(可运行)状态,它将向线程调度器注册这个线程。
调用start()方法并不一定马上会执行这个线程,正如上面所说,它只是进入Runnable 而不是Running。
注意,不要直接在程序中调用线程的run()方法。
为了规范,一定要给自己创建的线程命名!!!
JAVA里面多线程的创建有下面两种方法:
(Java语言在设计之初就加入了对线程的支持,开发人员可以使用JDK提供的相关API创建基于多线程的应用程序
每个Java程序启动后,虚拟机将自动创建一个主线程,也可以通过以下两种方式自定义线程类:
创建java.lang.Thread类的子类,重写该类的run方法
创建java.lang.Runnable接口的实现类,实现接口中的run方法
)
通过java.lang.Thread来创建一个线程
Thread类-2
Thread类中的重要方法:
run方法:包括线程运行时执行的代码,通常在子类中重写它。
start方法:启动一个新的线程,然后虚拟机调用新线程的run方法
采用implements Runnable方法创建线程
由于继承了Thread后,类再不能继承别的类,所以一般我们采用实现Runnable接口的方法来创建线程。
提供一个实现接口Runnable的类,实现run()方法。
得到这个类的实例A。
New 这个一个Thread对象,同时A作为参数传入。
例如:Thread runner=new Thread(A);
调用start启动线程
例如:runner.start();
Runnable接口
java.lang.Runnable接口中只有一个未实现的run方法,实现该接口的类必须重写该方法。
Runnable接口与Thread类之间的区别
Runnable接口必须实现run方法,而Thread类中的run方法是一个空方法,可以不重写
Runnable接口的实现类并不是真正的线程类,只是线程运行的目标类。要想以线程的方式执行run方法,必须依靠Thread类。
启动线程:
每个线程都是通过某个特定Thread对象所对应的方法run( )来完成其操作的,方法run( )称为线程体。
使用start()方法,线程进入Runnable(可运行)状态,它将向线程调度器注册这个线程。
调用start()方法并不一定马上会执行这个线程,正如上面所说,它只是进入Runnable 而不是Running。
注意,不要直接在程序中调用线程的run()方法。
线程的生命周期
指线程从创建到启动,直至运行结束这段时间
可以通过调用Thread类的相关方法影响线程的运行状态
线程的运行状态:
新建(New)
可执行(Runnable)
运行(Running)
阻塞(Blocking)
死亡(Dead)
新建状态(New)
当创建了一个Thread对象时,该对象就处于“新建状态”
没有启动,因此无法运行
可执行状态(Runnable)
其他线程调用了处于新建状态线程的start方法,该线程对象将转换到“可执行状态”
线程拥有获得CPU控制权的机会,处在等待调度阶段。
运行状态(Running)
处在“可执行状态”的线程对象一旦获得了CPU控制权,就会转换到“执行状态”
在“执行状态”下,线程状态占用CPU时间片段,执行run方法中的代码
处在“执行状态”下的线程可以调用yield方法,该方法用于主动出让CPU控制权。线程对象出让控制权后回到“可执行状态”,重新等待调度。
阻塞状态(Blocking)
线程在“执行状态”下由于受某种条件的影响会被迫出让CPU控制权,进入“阻塞状态”。
进入阻塞状态的三种情况:
调用sleep方法(调用sleep方法
public void sleep(long millis)
Thread类的sleep方法用于让当前线程暂时休眠一段时间
参数millis的单位是毫秒
调用join方法(将多线程又变成单线程)(调用join方法(合并某个线程)
处在“执行状态”的线程如果调用了其他线程的join方法,将被挂起进入“阻塞状态”
目标线程执行完毕后才会解除阻塞,回到“可执行状态”
执行I/O操作
线程在执行过程中如果因为访问外部资源(等待用户键盘输入、访问网络)时发生了阻塞,也会导致当前线程进入“阻塞状态”。
)
执行I/O操作
解除阻塞
睡眠状态超时
调用join后等待其他线程执行完毕
I/O操作执行完毕
调用阻塞线程的interrupt方法(一般不调用这个方法)
死亡状态(Dead)
处于“执行状态”的线程一旦从run方法返回(无论是正常退出还是抛出异常),就会进入“死亡状态”。
已经“死亡”的线程不能重新运行,否则会抛出IllegalThreadStateException
可以使用Thread类的isAlive方法判断线程是否活着
线程调度
按照特定机制为线程分配CPU时间片段的行为
Java程序运行时,由Java虚拟机负责线程的调度
线程调度的实现方式
分时调度模型(CPU默认的方法):让所有线程轮流获得CPU的控制权,并且为每个线程平均分配CPU时间片段
抢占式调度模型:选择优先级相对较高的线程执行,如果所有线程的优先级相同,则随机选择一个线程执行。Java虚拟机采用此种调度模型。
“synchronized”关键字:
为了防止共享对象在并发访问时出现错误,Java中提供了“synchronized”关键字。
synchronized关键字
确保共享对象在同一时刻只能被一个线程访问,这种处理机制称为“线程同步”或“线程互斥”。Java中的“线程同步”基于“对象锁”的概念
当一个线程访问对象的同步方法时,被访问对象就处于“锁定”状态,访问该方法的其他线程只能等待
可以加在方法前,还可以加在代码块里面。
以上是关于线程的创建和运行的主要内容,如果未能解决你的问题,请参考以下文章