线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
进程和线程区分:
- 进程有自己独立的地址空间,而线程没有,线程必须依赖于进程而存在。
- 线程与资源分配无关,它属于某一个进程,并与进程内的其他线程一起共享进程的资源。
- 进程是程序在某个数据集合上的一次运行活动;线程是进程中的一个执行路径。
单一线程(上面左图)只有主线程一条执行路径,多线程(上面右图)是多条执行路径,主线程和子线程并行交替执行
创建多线程的三种方式
- 继承Thread类【重点】
- 自定义线程类继承Thread类
- 重写run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
//自定义线程类继承Thread类
public class TestThread extends Thread{
//重写run()方法,编写线程执行体
@Override
public void run(){
for (int i = 0;i < 10;i++){
System.out.println("run方法执行");
}
}
public static void main(String[] args) {
//main线程是主线程
//创建一个线程对象
TestThread testThread = new TestThread();
//调用start()方法开启子线程
testThread.start();
for (int i=0;i<200;i++){
System.out.println("主线程执行");
}
}
}
运行结果(并行交替执行)
主线程执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
主线程执行
主线程执行
主线程执行
…
注意:线程开启不一定立即执行,由CPU调度执行
//特别注意如果创建的线程对象调用的不是start(),而是run(),并不是多线程
testThread.run();
运行结果(执行完run方法才回到main方法继续执行下去)
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
主线程执行
…
- 实现Runnable接口【重点】
- 自定义MyRunnable类实现Runnable接口
- 重写run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
Thread类也是实现了Runnable接口,尽量面向接口编程
public class TestThread2 implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("run方法执行");
}
}
public static void main(String[] args) {
//main线程是主线程
TestThread2 testThread2 = new TestThread2();
//new Thread(testThread2).start()简化下面两行代码
//创建一个线程代理对象(静态代理),把自定义类的实列化对象放Thread构造器中(传入目标对象)
Thread thread = new Thread(testThread2);
//代理对象调用start()方法开启线程
thread.start();
for (int i = 0; i < 200; i++) {
System.out.println("主线程执行");
}
}
}
运行结果(并行交替执行)
主线程执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
run方法执行
主线程执行
主线程执行
run方法执行
run方法执行
run方法执行
主线程执行
…
第二种方式避免了JAVA单继承局限性,灵活方便,方便同一个对象被多个线程使用(推荐使用)
//多个线程同时操作一个对象(买车票案例)
public class TestThread3 implements Runnable{
//操作的对象
private int ticketNumbers = 10;
@Override
public void run(){
while(true){
if(ticketNumbers<=0){
break;
}
//Thread.currentThread().getName()获取线程名字
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNumbers--+"票");
}
}
public static void main(String[] args) {
//创建目标对象
TestThread3 testThread3 = new TestThread3();
//这里可以理解为run方法为事件,三个人(代理对象)同时执行就是多事件(事件不一样,因为人都不一样了)的同时执行,就是对多线程的通俗理解
new Thread(testThread3,"小红").start();
new Thread(testThread3,"小明").start();
new Thread(testThread3,"小亮").start();
}
}
继承Thread类也可以实现处理同一个共享资源,有兴趣的可以看看这个案例代码
- 实现Callable接口【了解,因为我也不太会了】
- 自定义MyCallable类实现Callable接口
- 重写call()方法,编写线程执行体(与上面两种方式不同的是call有返回值,需要抛出异常)
- 创建目标对象
- 创建执行服务
- 提交执行
- 获取结果
- 关闭服务
public class TestThread4 implements Callable<Boolean> {
//操作的对象
private int ticketNumbers = 10;
@Override
public Boolean call(){
while(true){
if(ticketNumbers<=0){
break;
}
//Thread.currentThread().getName()获取线程名字
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNumbers--+"票");
}
return true;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestThread4 t1 = new TestThread4();
TestThread4 t2 = new TestThread4();
TestThread4 t3 = new TestThread4();
//创建执行服务
ExecutorService executorService = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> r1 = executorService.submit(t1);
Future<Boolean> r2 = executorService.submit(t2);
Future<Boolean> r3 = executorService.submit(t3);
//获取结果
boolean rs1 = r1.get();
boolean rs2 = r2.get();
boolean rs3 = r3.get();
//关闭服务
executorService.shutdown();
}
}