从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。–Wikipedia
程序: 是含有指令和数据的文件
,被存储在磁盘
或其他的数据存储设备中。
进程诞生背景:
1,在多道程序环境
下,允许多个程序并发
执行,此时它们将失去封闭性,并具有间断性及不可再现性的特征。
2,为此引入了进程(Process)的概念,以便更好地描述和控制程序的并发执行,实现操作系统的并发性和共享性。
进程的定义为:
运行过程
,是系统进行资源分配和调度的一个独立单位。内存空间
,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。线程诞生背景:
1,引入进程的目的,是为了使多道程序并发执行,以提高资源利用率和系统吞吐量;
2,而引入线程,则是为了减小程序在并发执行时所付出的时空开销,提高操作系统的并发性能。
线程的定义为:
更小
的执行单位。多个
线程。共享
同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程
。理解:
1,你的公司这个整体是个操作系统;
2,公司有多个部门,一个部门下有多个小组,每个小组是一个进程;
3,每个小组下有多个成员,每个成员就是一个线程;
4,当一个项目A下来的时候,公司把A项目拿个你所在技术部的第一小组做;
5,小组就是一个进程,小组中的每个成员就是一个线程。
主要有两种方式:
注意:
每个线程,都有自己的名字。main方法作为主线程,线程名就是“main”,其他新建线程也有名字,默认是“Thread-0”,“Thread-1”类此递增。
操作步骤:
类方法:
第一个Thread类继承实现的多线程:
public class Main {
public static void main(String[] args) {
//创建第一个线程实例
MyThread mt = new MyThread();
// 修改线程名字
mt.setName("第一个线程运行");
// 启动线程
mt.start(); //告诉系统创建一个独立的线程来运行这个实例中的run方法
// 创建第二个线程实例
MyThread mt2 = new MyThread();
mt2.setName("第二个线程运行");
// 启动线程
mt2.start(); //告诉系统又创建一个独立的线程来运行这个实例中的run方法
}
}
class MyThread extends Thread {
@Override
public void run() {//
for (int i = 0; i < 5; i++) {
System.out.println(getName() + ":" + i);
}
}
}
//注意:每次运行的结果都是不一样的
操作步骤:
第一个Runnable接口实现的多线程:
public class Main {
public static void main(String[] args) {
//创建线程实例
MyThread mt = new MyThread();
Thread t = new Thread(mt);
// 修改线程名字
t.setName("张三");
// 启动线程
t.start();
// 创建线程实例
MyThread mt2 = new MyThread();
Thread t2 = new Thread(mt2);
t2.setName("老王");
// 启动线程
t2.start();
}
}
class MyThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
问题:为什么需要定一个类去实现Runnable接口呢?继承Thread类和实现Runnable接口有啥区别呢?
解答:
public class Main {
public static void main(String[] args) {
//继承方式 XXX extends Thread{ public void run(){}}
new Thread() {
public void run() {
System.out.println("!!!");
}
}.start();
// 实现接口方式 XXX implements Runnable{ public void run(){}}
Runnable r = new Runnable() {
public void run() {
System.out.println("###");
}
};
new Thread(r).start();
//简写法
new Thread(new Runnable() {
public void run() {
System.out.println("@@@");
}
}).start();
}
}
根据Thread.State的静态内部类枚举,线程分为六种状态:
如何获取线程状态
public class Hello {
public static void main(String[] args) {
MyThread mth = new MyThread();
Thread th = new Thread(mth); //线程0
System.out.println(th.getState()); //执行过new以后,线程的状态就为NEW
th.start();
System.out.println(th.getState());
}
}
class MyThread implements Runnable {
@Override
public void run() {
System.out.println("启动线程:"+Thread.currentThread().getName());
}
}
停止线程的思想方法:
A. 标志位法
B. Thread类的stop方法(已过时,禁止使用!)
C.抛异常法
D.线程中段法(见下文)
核心要点:
设置一个标志位,停止线程
public class Hello {
public static void main(String[] args) {
MyThread mth = new MyThread();
Thread th0 = new Thread(mth); //线程0
th0.start();
//让线程th0运行3秒钟,自动停止
try {
Thread.sleep(3000);
} catch(InterruptedException e) {
e.printStackTrace();
}
mth.stopCurrentThread();
}
}
class MyThread implements Runnable {
//volatile修饰符用来保证其它线程读取的总是该变量的最新的值
private volatile boolean exitFlag = false;
public void stopCurrentThread() {
exitFlag = true;
}
@Override
public void run() {
while(!exitFlag) {
System.out.println("线程:"+Thread.currentThread().getName()+"正在运行...");
}
System.out.println("线程:"+Thread.currentThread().getName()+"停止运行");
}
}
void interrupt();
中断此线程。static boolean interrupted();
检查当前线程是否被中断,重置当前线程的中断状态为false;boolean isInterrupted();
检查某线程是否已经中断。线程中断来停止线程
public class Hello {
public static void main(String[] args) {
MyThread mth = new MyThread();
Thread th0 = new Thread(mth); //线程0
th0.start();
//让线程th0运行3秒钟,自动停止
try {
Thread.sleep(3000);
} catch(InterruptedException e) {
e.printStackTrace();
}
th0.interrupt(); //向th0线程发送终止通知
}
}
class MyThread implements Runnable {
@Override
public void run() {
while(!Thread.interrupted()) {
System.out.println("线程:"+Thread.currentThread().getName()+"正在运行...");
}
System.out.println("线程:"+Thread.currentThread().getName()+"停止运行");
}
}
什么是守护线程:
Boolean isDaemon();
检查此线程是否为守护线程。
void setDaemon(Boolean isDaemon);
设定该线程为守护线程
守护线程用法
public class Hello {
public static void main(String[] args) {
MyThread mth = new MyThread();
Thread th0 = new Thread(mth); //线程0
Thread th1 = new Thread(mth); //线程1
th0.start();
System.out.println("th0是守护线程?"+th0.isDaemon());
th1.setDaemon(true); //先设置为守护线程,再启动
th1.start();
System.out.println("th1是守护线程?"+th1.isDaemon());
}
}
class MyThread implements Runnable {
@Override
public void run() {
System.out.println("我是线程:" + Thread.currentThread().getName());
}
}
操作方法(java.lang.Thread类):
可选值:
数字越大,优先级越高:有效范围在1~10之间
线程优先级使用示例
public class Hello {
public static void main(String[] args) {
MyThread mth = new MyThread();
Thread th0 = new Thread(mth); //线程0
Thread th1 = new Thread(mth); //线程1
th0.setPriority(10); //先设定优先级,再启动
th0.start();
System.out.println("线程th0的优先级:"+th0.getPriority());
th1.setPriority(5);
th1.start();
System.out.println("线程th1的优先级:"+th1.getPriority());
}
}
class MyThread implements Runnable {
@Override
public void run() {
System.out.println("我是线程:" + Thread.currentThread().getName());
}
}
为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?
new
一个 Thread,线程进入了新建
状态;start()
方法,会启动一个线程并使线程进入了就绪
状态,当分配到时间片后就可以开始运行了。