.进程&线程(&java.lang.Thread)详解
一.进程与线程
进程
我们在进行操作电脑的时候,通常会打开浏览器,通讯工具等应用程序,这个时候CPU通过作业调度在内存中就会分配一些空间让它们处于宏观上的运行状态(处于可以被CPU执行的状态),而这部分空间资源就可以说是相应的进程占据的,很显然运行不同的程序需要不同的进程,在内存中也为它们分配独立,无共享的区域。静态描述进程的是PCB快(数据结构集),它是系统感知进程存在的唯一实体,通常包含进程名(或者标识符),用户名(或者用户标识号),家族关系。
进程的状态
就绪态:进程获得了除cpu以外的其他资源,进入抢占cpu的队列中
执行态:cpu正在执行该进程
阻塞态:进程继续执行的某个事件条件(如I/O设备)尚未具备
挂起态:处理机调度将进程调离内存进入外存
终止态:进程结束。(当我们撤销一个进程的时候,会通过PCB结构递归删除所有它的子进程,否者子进程可能处于无法控制的状态。)
(撤销进程的流程)
进程阻塞与挂起
阻塞详细流程图:
阻塞与挂起的区别:
1.首先阻塞是被动行为,当资源完备后,任然受cpu调度进入就绪状态,而挂起是主动行为,进程外存后,不受cpu作业调度,通过resume()函数进入就绪态。
2.发生原因不同:阻塞原因是针对这单个进程等待发生的条件不具备,而挂起原因内存资源有限暂时调离内存的过程。
线程
线程也称为轻型进程。线程的作用域在单个特定的线程内。一个进程内支持多个线程。这些线程的特点是:共享一定的内存区和数据。它们是彼此相互独立的,可以并发进行,宏观上看来是同时运行的,但实际上CPU在一个时刻只能处理一个子任务,分时操作系统采用了“时间片的策略”,即CPU将时间切割为时间片,然后将这些时间片分配给这些程序,只有获得时间片的程序才被执行。还有一个概念叫做主线程,它是进程初始化后自动启动的线程,如java里面的main。
进程与线程的区别
资源方面:一个进程包含多个线程,同类的多个线程共享一块内存和数据资源,而进程之间(包括子进程与父进程之间)是完全独立的,不存在资源的共享。
功能方面:进程是并发程序执行过程中资源分配的基本单元,线程是程序运行与调度的基本单元。
处理机的调度
(图片来自:http://www.cnblogs.com/dyllove98/p/3249243.html)
cpu调度发生的情况总结:
(1)创建进程:将进程读入内存中;
(2)进程终止:每当一个进程终止时,必须进行调度;从就绪队列中选择要执行的下一个进程;
(3)等待事件:运行进程由于等待I/O、信号量或其他原因不能继续,这时cpu对I/O设备发出启动指令,并将当前进程调入等待区;
(4)中断发生:当I/O设备完成时后会发出I/O中断,CPU完成中断响应,之后进行现场保护,中断服务,中断返回一系列调度;
(5)运到到时:当进程进程分配的时间片用完,此时选择新的进程投入运行。
(很明显挂起的进程不需要cpu进行作业调度)
二.进程的优先级
对于所有线程都具有它自己的优先级,优先级高的首先被CPU执行,当某个线程处于运行状态时,那些尚未拥有优先级的处于可运行状态的线程会自动获得优先级。还存在另一种情况,当某个线程在运行时,一个更高优先级的线程处于可运行状态,这是这个线程被立即执行,这称为先占式调度。
三.线程的开发方法
1.实现Runnable接口实现它的run()方法
2.继承Thread类,覆盖它的run()方法----Thread已经实现了Runnable接口实现了run方法,因此继承Thread的类是覆盖run()方法
(Runnable实现线程解决了java单一继承的局限性)
Thread/Runnable原理请看本人另一博客http://www.cnblogs.com/kundeg/p/6576094.html
四.线程池
背景:例如web服务器,数据库服务器,文件服务器等服务器端应用程序,都面临这来着客户端的请求,这些请求的整体特点是:单个任务处理的时间很短,但是请求的数目巨大
瓶颈:对于在进程内划分线程已经是个很大的改进,但仍然存在以下问题,对于每个到达服务器端的请求,单独为它们创建一个线程,将请求处理完后,再将线程销毁,然后线程创建与销毁的时间比处理请求的时间要多得多。同时线程过多,也会消耗内存。
改进:初始的时候便创建一个线程池(拥有i个线程),当请求到达时便拥有线程池中的某个线程(免去了创建时间),当线程池中的所有线程都被占据的时候,其他请求需要等待,占据线程的请求处理完后,线程又空余出来,新的请求可以进入。此处会有一定的等待时间,但和原来繁琐的线程创建和销毁相比,性能改进不少,同时线程池的构建也需要不断优化。
五.线程的状态以及运行控制
线程的运行状态
上述表明了线程在运行过程中的5种状态:
初始化状态:通过new实例化了一个线程对象,但该对象是空的并没有分配资源
可运行状态:通过start()方法,为该线程分配了除了CPU外的所需资源(进入队列,排队等待CPU),处于Runnable状态
运行状态:线程调度控制CPU处理一个Runnable线程,这个时候才实际上执行run()函数的代码
阻塞状态:正在运行的线程由于某些事件尚未具备(例如:输入输出)从而进入进入阻塞状态,来到阻塞池等待
挂起状态: A,通过调用sleep()方法使线程进入休眠状态,线程在指定时间内不会运行。
B,通过调用join()方法使线程挂起,如果某个线程在另一个线程t上调用t.join(),这个线程将被挂起,直到线程t执行完毕为止。
C,通过调用wait()方法使线程挂起,直到线程得到了notify()和notifyAll()消息,线程才会进入“可执行”状态。
(区别进程的挂起,线程不拥有资源,也不存在将资源放入外存中)
死亡状态:线程结束了(Dead),可由这些原因导致:1.该线程运行完毕。2.意外退出。3.父类线程控制其消亡。
线程的运行控制
1.线程的启动start()
- public class test extends Thread{
- public void run(){
- while(true){
- System.out.println("子线程运行中---");
- }
- }
- }
- public static void main(String args[]){
- test t =new test();
- t.start();
- try{
- Thread.sleep(2000);//父线程进入等待池等待
- }
- catch(Exception e ){
- }
- t.stop();
- }//在上述实例中,通过main主线程创建了一个子线程,他们是相互独立,并发执行,但是父线程可以控制子线程的状态,例如stop()
2.休眠(sleep)与挂起(yield),join
相同:休眠与挂起都会使线程暂停处于等待状态
区别:休眠可以设定时间,并且期间任何优先级的线程都可以由可运行状态变为可执行状态,而挂起不可以设定时间,只有同等优先级的线程可以变成可执行状态
join立即执行方法
- class test1 extends Thread{
- static int count = 0;
- public void run(){
- for(int i=0;i<5;i++){
- count++;
- }
- }
- }
- public class join {
- public static void main(String ats[]){
- test1 t = new test1() ;
- try {
- t.start();
- t.join();//如果没有这条语句输出为0,当前输出为5
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println(test1.count);
- }
- }
3.synchronized()
1.当两个并发线程访问同一个对象中的这个synchronized(this)同步代码块时,首先访问的线程获得对象锁,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块
- public class synchronized1 implements Runnable {
- public void run() {
- synchronized(this) {
- for (int i = 0; i < 5; i++) {
- System.out.println(Thread.currentThread().getName() + " 执行" );
- }
- }
- }
- public static void main(String[] args) {
- synchronized1 t1 = new synchronized1();
- Thread ta = new Thread(t1, "A");
- Thread tb = new Thread(t1, "B");
- ta.start();
- tb.start();
- }
- }
- //结果
- B执行
- B执行
- B执行
- B执行
- B执行
- A执行
- A执行
- A执行
- A执行
- A执行
2.当一个线程访问一个类对象的一个synchronized(this)同步代码块时,获得对象锁,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
- public class synchoronized2 {
- public void syn() {
- synchronized(this) {
- for(int i=0;i<5;i++){{
- System.out.println(Thread.currentThread().getName() + "执行ing");
- try {
- Thread.sleep(500);
- } catch (InterruptedException ie) {
- }
- }
- }
- }
- }
- public void notSyn() {
- for (int i = 0; i < 5; i++) {
- System.out.println(Thread.currentThread().getName() +"执行ing");
- try {
- Thread.sleep(500);
- } catch (InterruptedException ie) {
- }
- }
- }
- public static void main(String[] args) {
- synchoronized2 s2 = new synchoronized2();
- Thread t1 = new Thread(new Runnable() {
- public void run() {
- s2.syn();
- }
- }, "t1");
- Thread t2 = new Thread(new Runnable() {
- public void run() {
- s2.notSyn();
- }
- }, "t2");
- t1.start();
- t2.start();
- }
- }
- //结果
- t2执行ing
- t1执行ing
- t2执行ing
- t1执行ing
- t1执行ing
- t2执行ing
- t2执行ing
- t1执行ing
- t1执行ing
- t2执行ing
3.当一个线程访问一个对象的一个synchronized(this)同步代码块时,获得对象锁,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞
- public class synchronized3 {
- public void syn1() {
- synchronized (this) {
- for(int i=0;i<5;i++) {
- System.out.println(Thread.currentThread().getName() + "执行ing");
- try {
- Thread.sleep(500);
- } catch (InterruptedException ie) {
- }
- }
- }
- }
- public void syn2() {
- //synchronized修饰方法,结果一样
- synchronized (this) {
- for(int i=0;i<5;i++) {
- System.out.println(Thread.currentThread().getName() + "执行ing");
- try {
- Thread.sleep(500);
- } catch (InterruptedException ie) {
- }
- }
- }
- }
- public static void main(String[] args) {
- synchronized3 s = new synchronized3();
- Thread t1 = new Thread(new Runnable() {
- public void run() {
- s.syn1();
- }
- }, "t1");
- Thread t2 = new Thread(new Runnable() {
- public void run() {
- s.syn2();
- }
- }, "t2");
- t1.start();
- t2.start();
- }
- }
- //结果
- t1执行ing
- t1执行ing
- t1执行ing
- t1执行ing
- t1执行ing
- t2执行ing
- t2执行ing
- t2执行ing
- t2执行ing
- t2执行ing
4.区别对象锁和类锁:对象锁和类锁互不干扰,一个线程可以同时具有对象锁和类锁
- public class synchronized4 {
- public static instancet i = new instancet();
- public static instancet getI() {
- return i;
- }
- public static void main(String args[]) {
- Thread t1 = new Thread(new tt(), "t1");
- Thread t2 = new Thread(new tt(), "t2");
- Thread t3 = new Thread(new tt(), "t3");
- Thread t4 = new Thread(new tt(), "t4");
- t1.start();
- t2.start();
- t3.start();
- t4.start();
- }
- }
- class tt implements Runnable {
- public void run() {
- if (Thread.currentThread().getName().equals("t1")) {
- synchronized4.getI().getClassLock(Thread.currentThread().getName());
- } else if (Thread.currentThread().getName().equals("t2")) {
- synchronized4.getI().getObjectLock(Thread.currentThread().getName());
- } else if (Thread.currentThread().getName().equals("t3")) {
- synchronized4.getI().getClassLock(Thread.currentThread().getName());
- } else {
- synchronized4.getI().getObjectLock(Thread.currentThread().getName());
- }
- }
- }
- class instancet {
- public synchronized void getObjectLock(String s) {
- System.out.println(s + "获得对象锁");
- try {
- Thread.sleep(2000);//线程进入休眠,但仍然具有对象锁
- } catch (Exception e) {
- }
- }
- public synchronized static void getClassLock(String s) {
- System.out.println(s + "获得类锁");
- try {
- Thread.sleep(4000);
- } catch (Exception e) {
- }
- }
- }
- //结果
- t2获得对象锁
- t1获得类锁
- t4获得对象锁
- t3获得类锁
4.sleep(time),经过一段时间后自动唤醒,sleep后线程进入不可执行状态,但仍然具有锁,对其他线程有阻塞作用
上述代码已经说明sleep的作用
5.wait()与notify(),wait()线程进入休眠且放弃锁
- public class synchronized7 {
- public static void main(String[] args) {
- new Thread(new Thread1()).start();
- try {
- Thread.sleep(2000);
- } catch (Exception e) {
- e.printStackTrace();
- }
- new Thread(new Thread2()).start();
- }
- private static class Thread1 implements Runnable{
- @Override
- public void run(){
- synchronized (synchronized7.class) {
- System.out.println("线程1正在执行ing");
- try {System.out.println("线程1进入休眠");
- synchronized7.class.wait();//休眠且放弃锁
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("线程1继续执行");
- System.out.println("线程1结束"); }
- }
- }
- private static class Thread2 implements Runnable{
- @Override
- public void run(){
- synchronized (synchronized7.class) {
- System.out.println("线程2正在执行ing");
- synchronized7.class.notify();
- try {
- Thread.sleep(5000);
- } catch (Exception e) {
- e.printStackTrace();
- }
- System.out.println("线程2继续执行");
- System.out.println("线程2结束");
- }
- }
- }
- }
- //结果
- 线程1正在执行ing
- 线程1进入休眠
- 线程2正在执行ing
- 线程2继续执行
- 线程2结束
- 线程1继续执行
- 线程1结束
6.wait()与sleep()区别
- public class waitandsleep extends Thread{
- static int number = 10;
- public void firstMethod() throws Exception {
- synchronized (this) {
- number += 100;
- System.out.println(number);
- }
- }
- //下面是否加上static,又是一种同步锁,结果不一样
- public synchronized void secondMethod() throws Exception {
- /**用于区别wait和sleep
- *1.sleep(在Thread的静态方法)的时候仍然占有机锁,释放cpu
*2.wait(Object的方法)的时候释放机锁,其他线程块可以进入,释放cpu
**/- //Thread.sleep(2000);//输出2100
this.wait(2000);//输出110- number *= 200;
- }
- public void run() {
- try {
- firstMethod();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) throws Exception {
- waitandsleep ws=new waitandsleep();
- ws.start();
- ws.secondMethod();
ps:纯手打,图片是拍的书上的,勉强看的清楚,感觉自己写博文一直有个弊端,试图在一篇文章里面囊括一个大的知识工厂,但现在发现能将一个点讲清楚就非常非常困难,所以这篇失败的博文,还将继续改善,fighting!!
更新+1+1+1
.进程&线程(&java.lang.Thread)详解的更多相关文章
- java.lang.Thread类详解
java.lang.Thread类详解 一.前言 位于java.lang包下的Thread类是非常重要的线程类,它实现了Runnable接口,今天我们来学习一下Thread类,在学习Thread类之前 ...
- Java提高班(一)Thread详解
一.概述 在开始学习Thread之前,我们先来了解一下 线程和进程之间的关系: 线程(Thread)是进程的一个实体,是CPU调度和分派的基本单位. 线程不能够独立执行,必须依存在应用程序中,由应用程 ...
- “全栈2019”Java多线程第九章:判断线程是否存活isAlive()详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Java 线程--继承java.lang.Thread类实现线程
现实生活中的很多事情是同时进行的,Java中为了模拟这种状态,引入了线程机制.先来看线程的基本概念. 线程是指进程中的一个执行场景,也就是执行流程,进程和线程的区别: 1.每个进程是一个应用程序,都有 ...
- “全栈2019”Java多线程第二十二章:饥饿线程(Starvation)详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第七章:等待线程死亡join()方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第五章:线程睡眠sleep()方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- Java类加载器详解
title: Java类加载器详解date: 2015-10-20 18:16:52tags: JVM--- ## JVM三种类型的类加载器- 我们首先看一下JVM预定义的三种类型类加载器,当一个 J ...
- Android查缺补漏(IPC篇)-- 进程间通讯之AIDL详解
本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...
- java异常处理机制详解
java异常处理机制详解 程序很难做到完美,不免有各种各样的异常.比如程序本身有bug,比如程序打印时打印机没有纸了,比如内存不足.为了解决这些异常,我们需要知道异常发生的原因.对于一些常见的异常,我 ...
随机推荐
- Spring Boot启动过程(二)
书接上篇 该说refreshContext(context)了,首先是判断context是否是AbstractApplicationContext派生类的实例,之后调用了强转为AbstractAppl ...
- linux下安装TensorFlow(centos)
一.python安装 centos自带python2.7.5,这一步可以省略掉. 二.python-pip pip--python index package,累世linux的yum,安装管理pyth ...
- 最简单的Linux虚拟机磁盘扩容方法
思路:1.虚拟机增加磁盘容量: 2.将增加的磁盘容量增加到系统分区中: 准备阶段: 下载Gparted软件:https://sourceforge.net/projects/gparted/files ...
- 2017-01-27-hibernate环境搭建
Hibernate的环境搭建(uid方式): 1:导入包 2:创建实体对象 3:hibernate的映射配置文件 4:hibernate的核心配置文件 5:创建测试类实现表的创建 2:创建实体对象-U ...
- 路由器安装ubuntu-16.04.1-server-amd64出现“无法安装busybox-initramfs”错误。向目标系统中安装busybox-initramfs软件包时出现一个错误。请检查/var/log/syslog或查看第四虚拟控制台以获得详细
公司的路由器要ubuntu服务器进行路由网络功能的管理,在安装的时候出现下面的错误提示: 安装ubuntu-16.04.1-server-amd64出现“无法安装busybox-initramfs”错 ...
- Unity3d获取游戏对象的几种方法
1.GameObject.Find() 通过场景里面的名子或者一个路径直接获取游戏对象. GameObject root = GameObject.Find("GameObject" ...
- EF+SQLSERVER控制并发下抢红包减余额(改进)
最近几年想必大家一听到哪里有抢红包可以抢,马上会拿起手机点去~~~~然后问题来了... 如何控制在同一时间保证数据库中扣减红包余额不会出错.之前我们的做法是直接锁程序,这样子带来的坏处就是等待时间太长 ...
- WebServerice
WebServerice是什么 web service是一个web应用程序的分支,是构建应用程序的普通模型,可以在支持Internet网络通信操作系统上实施. 它的原理主要是利用HTTP协议使数据在w ...
- block之---循环引用
block内部引用外界对象的原则:block会对他内部所有的强指针进行强引用. 验证原理: 在主控制器中modal出ModalVC控制器,ModalVC中有强引用的block属性,在block内部使用 ...
- python之字典常用语法
1. 创建字典 描述:生成字典 语法: dic={'k1':'v1'} 样例: dic=dict(k1='v1',k2='v2') dic={'k1':'v1','k2':'v2'} 2. 取键值ge ...