Java学习-进程与线程

从操作系统来讲,可以被民用的系统最早是DOS,但是传统的DOS系统有一个特征:电脑出现病毒之后系统会死机,因为传统的DOS系统采用的是单进程的处理方式。而后来到了windows时代,那么采用的是多进程的处理方式,在同一个时间段上会有多个程序并发执行,轮流强占CPU资源。

但是进程的启动和销毁还是很慢的。所以后来人们开始尝试在进程上做进一步的优化,那么就产生了线程的概念,即:线程是在进程基础之上扩充的。线程的启动和销毁将比进程更快,一个进程上是可以划分出多个线程的,而进程消失的话线程一定也会消失,Java是为数不多的支持多线程编程的语言之一。

  

如果要想实现多线程的开发,那么就必须像主类存在那样,也需要一个线程的主体类,但是这个类并不能单独定义,必须让其继承Thread类或者是实现Runnable接口(如果从实际的开发来讲一定是Runnable接口)。

4.1、继承Thread类

线程的主体类只需要通过extends关键字继承Thread类,那么这个类就可以用于线程的控制,当继承了Thread类之中用户还需要覆写Thread类之中的run()方法“public void run()”。

范例:定义线程的主体类


class MyThread extends Thread {

private String name ;  // 理解为对象的名字

public MyThread(String name) {

this.name = name ;

}

@Override

public void run() { // 线程的主方法

for (int x = 0 ; x < 10 ; x ++) {

System.out.println(this.name + ",x = " + x);

}

}

}

此时每一个MyThread类的对象都是一个线程,那么可以产生多个线程。

但是当线程主体类定义完成后,必须通过对象进行访问,但是调用的并不是类中的run()方法,而是Thread类的start()方法:“public void start()”。调用此方法就相当于调用了run()方法。

范例:启动多线程


public class TestDemo {

public static void main(String[] args) {

MyThread mtA = new MyThread("线程A") ;

MyThread mtB = new MyThread("线程B") ;

MyThread mtC = new MyThread("线程C") ;

mtA.start() ;

mtB.start() ;

mtC.start() ;

}

}

如果使用的是run()方法实际上只是一个方法的普通调用,将采用顺序的方式执行,而如果调用的是start()方法则表示将启动多线程,多个线程彼此之间并发运行。

疑问:通过简短的分析,应该已经知道多线程的基本运行过程了,但是为什么非要通过start()来调用run()呢?

为了方便理解,打开关于Thread类中start()方法的定义:


public synchronized void start() {

if (threadStatus != 0)

throw new IllegalThreadStateException();

group.add(this);

boolean started = false;

try {

start0();

started = true;

finally {

try {

if (!started) {

group.threadStartFailed(this);

}

catch (Throwable ignore) {

}

}

}

private native void start0();

本方法会抛出一个“IllegalThreadStateException”异常,但是如果是手工的使用throw抛出异常,应该使用try…catch处理才对。但是此时并没有强制性要求,因为通过观察“IllegalThreadStateException”继承结构:


java.lang.Object

java.lang.Throwable

java.lang.Exception

java.lang.RuntimeException

java.lang.IllegalArgumentException

java.lang.IllegalThreadStateException

因为RuntimeException子类,一般当一个线程被重复启动的时候就会抛出此异常。所以一个线程只能够启动一次。

可以发现在调用start()方法的时候会自动调用start0()方法,而在start0()方法的声明处发现有一个native关键字,那么此关键字表示的是,将通过本地的原始函数进行代码的实现。

线程的操作一定是需要进行CPU资源调度,每个操作系统的资源调度是不一样的,所以此方法实际上会由JVM实现,那么编写的时候只给出了一个抽象方法的名称,而具体的实现将根据不同的操作系统进行覆写,所以才实现可移植性。

         所以可以得出结论,当用户执行start()方法的时候意味着将进行操作系统的资源调配,调配之后才会执行run()方法,即:任何时候只要是启动多线程,都一定要使用Thread类之中的start()方法。

4.2、实现Runnable接口

类与类之间的继承并不推荐去使用,但是类实现接口是一个推荐的功能,在Java里面为了解决多线程的单继承局限问题,所以也提供有一个Runnable接口,用户只需要让线程的主体类实现Runnable接口即可。

范例:观察Runnable接口的定义结构


public interface Runnable {

public void run() ;

}

范例:使用Runnable定义线程主体类


class MyThread implements Runnable {

private String name ;

public MyThread(String name) {

this.name = name ;

}

@Override

public void run() { // 线程的主方法

for (int x = 0 ; x < 10 ; x ++) {

System.out.println(this.name + ",x = " + x);

}

}

}

通过之前的分析可以得出结论,只要是线程的启动一定要依靠Thread类的start()方法,如果说现在一个类直接继承了Thread类,那么可以继承下start()方法,但是此时实现的是Runnable接口,那么将没有start()可以被继承。那么下面来观察Thread类中构造方法的定义:“public Thread(Runnable target)”。发现可以接收一个Runnable接口子类对象。

范例:启动多线程


public class TestDemo {

public static void main(String[] args) {

MyThread mtA = new MyThread("线程A") ;

MyThread mtB = new MyThread("线程B") ;

MyThread mtC = new MyThread("线程C") ;

new Thread(mtA).start();

new Thread(mtB).start();

new Thread(mtC).start();

}

}

此时两者的功能是完全相同的,但是很明显,使用Runnable要比使用Thread更加的合理。

4.3、两种实现方式的区别(面试题)

通过一系列的分析之后已经清楚了多线程的两种实现方式,但是这两种方式从结构上讲一定使用的是Runnable,可是除了这一点之外,还有其它的区别吗?

那么首先来观察一下Thread类的定义:


public class Thread extends Object implements Runnable

发现原来Thread类也实现了Runnable接口,于是一件很有意思的事情发生了。

从结构上讲Thread是一个代理类的结构设计,但是又不那么完整。如果是一个纯粹的代理设计模式,那么用户应该调用的是Thread类的run()方法,但是现在调用的却是start()方法(并不是Runnable接口提供的方法),所以在整个操作之中虽然形式是代理结构,但是最终还是有差异的,而这个差异也是由于历史原因造成的。

除了这个基本的联系之外,还有一点不算区别的小区别:使用Runnable接口实现的多线程要比使用Thread类实现的多线程更容易表示出数据共享的概念。

范例:编写一个简单的卖票程序,利用Thread类实现(产生三个线程对象一起卖票)


package cn.mldn.demo;

class MyThread extends Thread {

private int ticket = 5 ;    // 假设有5张票

@Override

public void run() { // 线程的主方法

for (int x = 0 ; x < 20 ; x ++) {

if (this.ticket > 0) {

System.out.println("卖票:ticket = " + this.ticket --);

}

}

}

}

public class TestDemo {

public static void main(String[] args) {

new MyThread().start();// 一个线程

new MyThread().start();// 两个线程

new MyThread().start();// 三个线程

}

}

这个时候发现每一个线程对象都有各自的五张票进行售卖,不符合要求。

范例:利用Runnable接口实现


package cn.mldn.demo;

class MyThread implements Runnable {

private int ticket = 5 ;    // 假设有5张票

@Override

public void run() { // 线程的主方法

for (int x = 0 ; x < 20 ; x ++) {

if (this.ticket > 0) {

System.out.println("卖票:ticket = " + this.ticket --);

}

}

}

}

public class TestDemo {

public static void main(String[] args) {

MyThread mt = new MyThread() ;

new Thread(mt).start();// 一个线程

new Thread(mt).start();// 两个线程

new Thread(mt).start();// 三个线程

}

}

面试题:请解释出多线程两种实现方式的区别?分别编写程序进行说明?

· 多线程的两种实现方式:继承Thread类、实现Runnable接口;

· 如果继承了Thread类,那么会受到单继承局限,而且不方便表示出数据共享的概念,Thread类是Runnable接口的子类;

· 如果实现了Runnable接口,那么将不受到单继承的影响,同时可以方便的表示出数据共享的操作;

· 但是不管使用何种方式,最终一定要通过Thread类的start()方法才可以启动多线程。

时间: 2024-10-23 11:55:18

Java学习-进程与线程的相关文章

java学习笔记14--多线程编程基础1

本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为一个进程,例如:用字处理软件编辑文稿时,同时打开mp3播放程序听音乐,这两个独立的程序在同时运行,称为两个进程 进程要占用相当一部分处理器时间和内存资源 进程具有独立的内存空间 通信很不方便,编程模型比较复杂 多线程 一个程序中多段代码同时并发执行,称为多线程,线程比进程开销小,协作和数据交换容易

java中进程与线程--三种实现方式

一:进程与线程 概述:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进程运行时,内部可能包括多个顺序执行流,每个顺序执行流就是一个线程. 进程:进程是指处于运行过程中的程序,并且具有一定的独立功能.进程是系统进行资源分配和调度的一个单位.当程序进入内存运行时,即为进程. 进程的三个特点: 1:独立性:进程是系统中独立存在的实体,它可以独立拥有资源,每一个进程都有自己独立的地址空间,没有进程本身的运行,用户进程不可以直接访问其他进程的地址空间. 2:

关于Java中进程和线程的详解

一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消.反映了一个程序在 一定的数据 集上运行的全部动态过程.通过进程控制块(PCB)唯一的标识某个进程.同时进程占据着相应的资源(例如包 括cpu的使用 ,轮转时间以及一些其它设备的权限).是系统进行资源分配和调度的一个独立单位. 程序和进程之间的主要区别在于: 状态         是否具有资源

JAVA学习日志(线程)

1.进程和线程 进程: 运行一个速度,程序在内存分配了运行空间 线程: 在进程中还运行,多个线程之间可以相互的切换. 问题 进程和线程的关系? 进程包括线程. 2.单线程和多线程 (JAVA抢占) 单线程:只有一条路径,必须等第一个执行了才能执行第二个. 比如 排队吃饭.... 多线程: 有多条路径 ... 比如 食堂排队的多个窗口. 3.线程分为主线程和子线程** 主线程就相当于游戏中的主要任务. 子线程就相当于游戏中的分支任务. 列题: 4.线程的优先级别  Java中共有10个级别,1到1

Java的进程和线程

什么是进程? 一个进程就是在一个运行的程序,它有自己独立的内存空间,一组系统资源,每个进程的内部数据和状态都是独立的,例如在window是同时打开多个记事本,虽然它们所运行的程序代码都是一样的,但是所使用的内存空间是独立的,互不干扰. 什么是线程? 线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制;但与进程不同的是,同类的多个线程共享一块内存空间和一组系统资源,而线程本身的数据通常只有微处理器的寄存器数据,以及一个供程序执行时使用的堆栈 进程与线程的区别 进程:每个进程都有

【转】Java学习---深入理解线程池

[原文]https://www.toutiao.com/i6566022142666736131/ 我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间. 那么有没有一种办法使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务? 在Java中可以通过线程池来达到这样的效果.今天我们就来详细讲解一下Ja

java学习笔记15--多线程编程基础2

本文地址:http://www.cnblogs.com/archimedes/p/java-study-note15.html,转载请注明源地址. 线程的生命周期 1.线程的生命周期 线程从产生到消亡的过程 一个线程在任何时刻都处于某种线程状态(thread state) 线程生命周期状态图 诞生状态 线程刚刚被创建 就绪状态 线程的 start 方法已被执行 线程已准备好运行 运行状态 处理机分配给了线程,线程正在运行 阻塞状态(Blocked) 在线程发出输入/输出请求且必须等待其返回 遇到

java学习笔记之线程(一)

线程(一) 一.线程定义于组成: 1.创建任务和线程: 1 TaskThread task = new TaskThread(); // 创建任务 2 Thread taskThread = new Thread(task); // 根据任务创建对应的执行线程 2.任务 ,实现Runnable 接口 Override run()方法 1 class TaskThread implements Runnable{ 2 ... 3 public void run(){ 4 //执行体 ,告诉系统如何

python学习进程和线程中碰到的问题以及问题解惑

python中的os.getpid() os.getpid()是获取的是当前进程的进程号,os.getppid()是获取当前进程的父进程的进程号 python 中__name__ = '__main__' 的作用 eg: def main(): print "we are in %s"%__name__ if __name__ == '__main__': main() 这个函数定义了一个main函数,我们执行一下该py文件发现结果是打印出"we are in __main_