进程
正在运行中的程序。每个进程都拥有自己(独立)的系统资源、内存空间和地址空间
线程
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。
线程的生命周期
新建状态(new )、可运行状态(runnable)、运行状态(running )、阻塞状态(blocked)、终止状态(dead)
- 当线程处于新建状态的时候,表明此时线程的对象实例已经被创建,但是尚未取得运行线程所需要的资源
- 产生了对象的实例之后,一旦调用线程的start()方法,则线程就会进入可运行状态,表明该线程已经获得运行时所需要的系统资源,具备了被调度执行的条件,从而使该线程可以被调度执行。
- 线程的运行状态是指线程被JVM线程调度程序分配了CPU执行时间,使用run() (在执行了start()之后,,run()自启动)方法可以使线程进入运行状态。正在运行的线程随时可能由JVM线程调度程序送回可运行状态。
- 当线程的run()方法执行完毕后进入终止状态,处于该状态的线程不会再被调度执行。
- 阻塞状态通常用于线程之间的通信与同步控制。
创建线程
Java程序中的线程被设计为一个对象,该对象具有自己的生命周期,可以利用接口java.lang.Runnable、类java.lang.Thread、Callable接口 创建一个线程
通过java.lang.Thread创建线程
继承Thread类,重写 run() 方法(必须重写)
public class ThreadDemo extends Thread {
@Override
public void run() {
System.out.println("当前线程的是:"+this.getName());
}
public static void main(String[] args) {
ThreadDemo threadDemo = new ThreadDemo();
threadDemo.start();
}
}
- 优点:程序代码相对简单,缺点:java 单继承使用场景限制
实现Runnable接口,实现 run() 方法
public class RunnableDemo implements Runnable {
@Override
public void run() {
System.out.println("当前线程的是:"+Thread.currentThread().getName());
}
public static void main(String[] args) {
RunnableDemo runnableDemo = new RunnableDemo();
new Thread(runnableDemo).start();
}
}
Runnable创建线程:通过把Runnable的一个子类的实例作为参数传递 给Thread类的一个构造方法
优点:
- 符合面向对象的设计思想
从面向对象的设计角度看,Thread类是虚拟CPU 的封装,因而Thread类的子类是关于CPU行为的类,但是在继承Thread类的子类大多都是与CPU不相关的类,而实现Runnable接口的方法将不会影响到Thread体系
- 实现了Runnable接口的类可以 用extends继承其他的类
Callable接口创建线程:实现Callable 接口,使用FutureTask 进行包装,通过Thread的构造方法传入futureTask实例
package com.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ICallableTest implements Callable<Long> {
@Override
public Long call() {
Long id = Thread.currentThread().getId();
System.out.println("当前的线程是"+Thread.currentThread().getName());
return id;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ICallableTest ct = new ICallableTest();
FutureTask futureTask = new FutureTask(ct);
Thread t = new Thread(futureTask,"二货");
t.start();
System.out.println(futureTask.get());
}
}
实现Callable接口的 call() 方法是带返回值(方法体中必须return )的,通过futureTask的 get() 获得
Callable和Runnable 的区别:
- Runnable的 run() 方法没有返回值,而Callable得 call() 方法有返回值,且支持泛型
- Runnable 接口 的 run() 方法只能抛出运行时候得异常,且无法捕获处理;Callable 接口 call 方法允许抛出异常(throws Exception),可以获取异常信息
线程的优先级
线程优先级是指优先级越高,越有可能先执行,但只是建议先执行,具体什么时候执行由系统决定(既不能绝对的说线程的调度是按照优先级进行调度的)
例如在windows系统中,当一个优先级为5且处于可运行状态的线程在等待CPU资源的时,系统可能正在执行一个优先级为3的线程
- 设置线程的优先级
public final void setPriority(int newPriority) ;
- 获取线程的优先级
public final int getPriority( );
- 在Thread 类中定义了线程优先级的取值范围(1~10)
//静态成员变量
public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
public static final int MAX_PRIORITY = 10;
优先级高只是建议先执行
Priority.java
public class Priority extends Thread {
public Priority(String s){
setName(s);
}
public void run(){
System.out.println("线程:"+getName()+"----"+getPriority());
}
}
PriorityTest.java
public class PriorityTest {
public static void main(String[] args){
Priority p1 = new Priority("线程 1");
Priority p2 = new Priority("线程 2");
Priority p3 = new Priority("线程 3");
Priority p4 = new Priority("线程 4");
p1.setPriority(1);
p2.setPriority(2);
p3.setPriority(3);
p4.setPriority(4);
p1.start();
p2.start();
p3.start();
p4.start();
}
}
线程调度器
Java提供了一个线程调度器来监视所有程序中的所有运行的线程,并决定哪个线程应该运行,哪个线程应该排队等待。在线程的 调度器的决策过程中,它可以识别线程的两个特征:一个是线程的优先级别,另一个是守护标志
- 守护线程:一般具有一个较低的优先级别,并且当计算机中运行的线程减少的时,为一个或多个程序提供一项基本的服务。例如垃圾收集线程就是一个不断运行的守护线程,它由于JVM提供,通过扫描程序查找不再被访问的变量,并把这些变量的资源释放给系统
- 调度器的基本原则:如果只有守护线程在运行,JVM将退出。新线程将从创建它的线程那里继承优先级别和守护标志,调度器通过分析所有线程的优先级来决定哪个线程先运行。具有较高优先级的线程,能够在较低优先级的 线程之前执行(但并不绝对)。