线程:一个线程就是一个“执行流”,每个线程之间都可以按照顺序执行自己的代码,多个线程则同时运行着多份代码。
线程的出现:
- “并发编程”成为了“刚需”:
- 单核的CPU发展遇到了瓶颈,单核的算力已不足以应对生产,此时就需要多核CPU,而并发编程更能充分利用多核CPU的资源。
- 有些任务场景需要“等待IO”,为了让等待IO的时间能够去做一些其他的工作,也需要用到并发编程。
- 最然多进程可以实现“并发编程”,但是进程更加轻量化
- 创建线程比创建进程快;
- 销毁线程比销毁进程快;
- 调度线程比调度进程快。
- 线程虽比进程更加轻量,但后续又出现了“线程池”和“协程”
进程和线程的区别:
-
进程是包含线程的,每个进程中都有至少一个线程,即此进程的主线程。
-
进程之间不共享内存空间,但是线程之间共享内存空间。
-
进程是系统分配资源的最小单位,而线程是系统CPU调度的最小单位。
线程是操作系统中的概念,操作系统内核实现了线程这样的机制,并且对用户层提供了一些API供用户使用。Java标准库中Thread类可以视为是对操作系统提供的API进行了进一步的抽象和封装。
线程的创建
- 继承Thread类
//继承Thread创建一个线程类
class MyThread extends Thread{
@Override
public void run() {
//具体的业务执行代码
System.out.println("你好!");
}
}
//创建MyThread的实例
MyThread myThread = new MyThread();
//启动线程
myThread.start();
- 实现Runnable接口
//实现Runnable接口
class MyThread2 implements Runnable{
@Override
public void run() {
//具体业务执行代码
Thread thread = Thread.currentThread();
//输出线程名称
System.out.println("线程名称:"+thread.getName());
}
}
//创建Thread实例,并将Runnable对象作为参数
Thread thread = new Thread(new MyThread2());
//启动线程
thread.start();
以上两种方法:
- 继承 Thread 类, 直接使用 this 就表示当前线程对象的引用。
- 实现 Runnable 接口, this 表示的是 MyThread2 的引用. 需要使用 Thread.currentThread()。
- Runable其他变形
- 使用匿名内部类创建子类对象
//使用匿名内部类创建Thread子类对象
Thread thread1 = new Thread() {
@Override
public void run() {
System.out.println("变1");
}
};
- 使用匿名类创建 Runnable 子类对象
//使用匿名类创建 Runnable 子类对象
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("变2");
}
});
- 使用 lambda 表达式创建子类对象
// 使用 lambda 表达式创建 Thread 子类对象
Thread thread3 = new Thread(() -> {
System.out.println("变3");
});
- 带返回值的Callable
- 实现Callable新建线程
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableDemo1 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建Callable实例
MyCallable myCallable = new MyCallable();
//用于接受Callable结果的对象
FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
//创建新线程
Thread thread = new Thread(futureTask);
//启动线程
thread.start();
//接受新线程执行的结果
int result = futureTask.get();
System.out.println(Thread.currentThread().getName()+"--新线程返回的结果为:"+result);
}
}
class MyCallable implements Callable<Integer>{
@Override
public Integer call() throws Exception {
//生成随机数范围0~9
int randomNum = new Random().nextInt(10);
System.out.println(Thread.currentThread().getName()+"--随机数:"+randomNum);
return randomNum;
}
}
- 匿名Callable创建
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableDemo2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<String > futureTask = new FutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
//新线程执行的业务代码
String[] arrays = new String[]{"Java","MySQL","Thread"};
//随机返回一个字符串
String result = arrays[new Random().nextInt(3)];
System.out.println(Thread.currentThread().getName()+
"--字符串:"+result);
return result;
}
});
//创建新线程
Thread thread = new Thread(futureTask);
//启动线程
thread.start();
String result = futureTask.get();
System.out.println(Thread.currentThread().getName()+
"--新线程的返回值:"+result);
}
}
常见构造方法
方法 | 说明 |
---|---|
Thread() | 创建线程对象 |
Thread(Runnable target) | 使⽤ Runnable 对象创建线程对象 |
Thread(String name) | 创建线程对象,并命名 |
Thread(Runnable target, String name) | 使⽤ Runnable 对象创建线程对象,并命名 |
Thread(ThreadGroup group, Runnable target) | 线程可以被⽤来分组管理,分好的组即为线程组 |
Thread thread1 = new Thread();
Thread thread2 = new Thread(new MyRunnable());
Thread thread3 = new Thread("线程A");
Thread thread4 = new Thread(new MyRunnable(), "线程B");
- 线程分组的使用
import java.util.Random;
public class ThreadDemo12 {
public static void main(String[] args) {
//1、创建一个线程分组
ThreadGroup group = new ThreadGroup("thread_group");
//2、定义一个公共的任务(线程的任务)
Runnable runTask = new Runnable() {
@Override
public void run() {
//业务执行代码
//生成一个1-3秒的随机数
int num = (new Random().nextInt(3)+1);
try {
//执行num秒后结束
Thread.sleep(num*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+"--任务用时:"+num+"s");
}
};
//3、线程分组并分配业务
Thread threadA = new Thread(group,runTask);
Thread threadB = new Thread(group,runTask);
Thread threadC = new Thread(group,runTask);
//4、启动线程
threadA.start();
threadB.start();
threadC.start();
//所有全部结束后
while (group.activeCount()>0){
}
System.out.println("业务完成");
}
}