进程与线程
进程与线程
进程与线程
1.进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体;
2.线程是在进程基础上划分的更小的程序单元,线程是在进程基础上创建并且使用的,所以线程依赖于进程的支持;线程的启动速度比进程快,所以使用多线程进行并发处理的时候,其执行的性能高于进程;
继承 Thread 类实现多线程
多线程要执行的功能都应该在 run() 方法中进行定义,但是 run() 方法不能直接被调用,要想启动多线程必须使用 start() 方法完成
package com.test;
class MyThread extends Thread { // 得到了一个线程主体类
private String name ;
public MyThread(String name) { // 保存线程名称
this.name = name ;
}
@Override
public void run() { // 覆写run()方法
for (int x = 0 ; x < 5 ; x ++) {
System.out.println("【"+this.name+" - 线程】运行,x = " + x);
}
}
}
public class JavaDemo {
public static void main(String[] args) {
MyThread threadA = new MyThread("线程A") ;
MyThread threadB = new MyThread("线程B") ;
MyThread threadC = new MyThread("线程C") ;
threadA.start(); // 通过Thread类继承而来
threadB.start(); // 通过Thread类继承而来
threadC.start(); // 通过Thread类继承而来
}
}
运行结果:
此时,虽然调用的是 start() 方法,但是执行的是 run() 方法
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();
- 这时,会发现在 start() 方法中调用了 start0() 方法,而 start0() 方法只定义了方法名称,但是 start0() 方法使用了 native 进行了定义,表示此方法需要依赖于操作系统来实现
- 此时,会发现 start() 方法里面会抛出一个"IllegalThreadStateException"异常类的对象,但是程序没有使用 throws 或者是使用 try-catch 处理,所以该异常一定是 RuntimeException 的子类;
- 抛出该异常的条件:每一个线程类的对象只允许启动一次,若是重复启动,则会抛出 IllegalThreadStateException 异常
举个栗子
package com.test;
class MyThread extends Thread {
private String name ;
public MyThread(String name) {
this.name = name ;
}
@Override
public void run() {
for (int x = 0 ; x < 5 ; x ++) {
System.out.println("【"+this.name+" - 线程】运行,x = " + x);
}
}
}
public class JavaDemo {
public static void main(String[] args) {
MyThread threadA = new MyThread("线程A") ;
threadA.start();//第一次启动
threadA.start();//第二次启动
}
}
运行结果:
Runnable 实现多线程
基于 Runnable 接口实现多线程
Module java.base
Package java.lang
Interface Runnable
接口定义
@FunctionalInterface
public interface Runnable {
void run();
}
但是,此时不再继承 Thread 父类了,那么对于此时的 MyThread 类中也就不再支持 start()方法,所以此时需要使用 Thread 的构造方法 public Thread(Runnable target)
利用 Thread 的构造方法 public Thread(Runnable target) 启动多线程
package com.test;
class MyThread implements Runnable {
private String name ;
public MyThread(String name) {
this.name = name ;
}
@Override
public void run() {
for (int x = 0 ; x < 5 ; x ++) {
System.out.println("【"+this.name+" - 线程】运行,x = " + x);
}
}
}
public class JavaDemo {
public static void main(String[] args) {
Thread threadA = new Thread(new MyThread("线程A")) ;
Thread threadB = new Thread(new MyThread("线程B")) ;
threadA.start();
threadB.start();
}
}
运行结果:
此时,由于程序只是实现了 Runnable 接口对象,而不是继承 Thread 父类,避免了线程主体类单继承的局限
Callable 实现多线程
接口定义
@FunctionalInterface
public interface Callable<V> {
public V call() throws Exception;
}
此时,可以看到 Callable 接口定义的时候设置了一个泛型,并且此泛型的类型就是返回值的类型
基于 Callable 接口实现多线程
package com.test;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class MyThread implements Callable<String> {
@Override
public String call() throws Exception {
for (int i = 0; i < 5; i++) {
System.out.println("线程" + i + "执行中");
}
return "线程执行完毕";
}
}
public class JavaDemo {
public static void main(String[] args) throws Exception {
FutureTask<String> task = new FutureTask<>(new MyThread());
new Thread(task).start();
System.out.println(task.get());
}
}
运行结果:
Runnable 与 Callable 的区别
- java.lang.Runnable接口只提供一个 run() 方法,并且无返回值,于JDK1.0提出
- java.util.concurrent.Callable 接口提供有 call() 方法,可以有返回值,于JDK1.5之后提出