目录
一、什么是多线程?
线程与进程
进程与线程区别:
并发与并行
二、多线程的创建方式(三种方式)
第一种:继承Thread类方式创建
第二种:实现Runnable接口的方式创建
第三种:利用Callable接口和Future方式创建
三、线程中常见的成员方法
1.获取线程名称、设置线程名、获取当前线程对象与休眠指定线程:
2.设置线程优先级与获取线程优先级:
3.设置守护线程:守护线程会在其他线程执行完毕后延迟结束。
4.出让线程/礼让线程
5.插入线程/插队线程 :把指定线程插到当前线程之前执行
一、什么是多线程?
多线程可以划分为“多”和“线程”,那么什么是线程呢?
线程与进程
说起多线程,那么就不得不说什么是线程,而说起线程,又不得不说什么是进程。
- 进程:是指一个内存中运行的应用程序(一组指令的有序集合),当一个程序被加载到内存中之后就变成了进程(进程=程序+执行)。每个进程都有一个独立的地址空间,进程也是程序的一次执行过程,是系统运行程序和操作系统分配资源的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。进程的三种状态:
1.阻塞态:等待某个事件的完成
2.就绪态:等待系统分配CPU以便运行
3.执行态:占用CPU正在运行
- 线程:线程是进程中的一个执行单元,是进程的一个实体,是
CPU调度和分派的基本单位
。负责当前进程中程序的执行,与同属进程的其他线程共享进程拥有的全部资源。一个进程中至少有一个线程,一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。
进程与线程区别:
- 进程是cpu资源分配的最小单位,线程是cpu调度的最小单位。
- 一个程序至少有一个进程,一个进程至少有一个线程。线程依赖于进程才能运行
- 线程本身拥有很少资源(线程标识符、程序计数器、一组寄存器的值、堆栈),与同属进程的其他线程共享进程拥有的资源(代码段、数据段、打开的文件、I/O设备等)。
- 线程开销小,但一个线程死掉等于整个进程死掉,不利于资源管理和保护。而进程正好相反,开销大,但相对线程安全。
并发与并行
- 并发:同一时刻,多个指令在单个CPU上交替执行。
- 并行:同一时刻,多个指令在多个CPU上同时执行。
来个比喻:并发是一个人同时吃三个馒头,而并行是三个人同时吃三个馒头。
总结:
二、多线程的创建方式(三种方式)
第一种:继承Thread类方式创建
1.自己定义一个类,继承Thread 2.重写run方法 3.创建子类对象,启动线程
public class MyThread extends Thread{
@Override
public void run() {
//线程要执行的代码
for (int i = 0; i < 100; i++) {
//Thread.currentThread()获取当前线程对象
System.out.println(Thread.currentThread().getName()+"helloThread!");
}
}
}
public class threadcase1 {
public static void main(String[] args) {
/**
* 多线程第一种启动方式
* 1.自己定义一个类,继承Thread
* 2.重写run方法
* 3.创建子类对象,启动线程
*/
//创建线程
MyThread t1=new MyThread();
MyThread t2=new MyThread();
//为线程起名字
t1.setName("线程1");
t2.setName("线程2");
//启动线程
t1.start();
t2.start();
//并发执行,交替
}
}
第二种:实现Runnable接口的方式创建
1.自己定义一个类实现Runnable接口 2.重写run方法 3.创建自己类对象, 4.创建Thread类对象并开启线程
public class MtRunnable implements Runnable{
@Override
public void run() {
//线程要执行的代码
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"_"+"hello Runnable");
}
}
}
public class ThreadDemo {
/**
* 多线程第二种启动方式
* 1.自己定义一个类实现Runnable接口
* 2.重写run方法
* 3.创建自己类对象,
* 4.创建Thread类对象并开启线程
*/
public static void main(String[] args) throws InterruptedException {
//创建自己类对象
//表示多线程要执行的任务
MtRunnable mr=new MtRunnable();
//创建线程对象
Thread t1=new Thread(mr);
Thread t2=new Thread(mr);
//给线程设置名字
t1.setName("01");
t2.setName("02");
//开启线程
t1.start();
t2.start();
//并发,交替执行
}
}
第三种:利用Callable接口和Future方式创建
1.创建一个MyCallable类实现Callable接口 2.重写call方法(有返回值,表示多线程运行的结果) 3.创建MyCallable类对象(表示多线程要执行的任务) 4.创建Future接口的实现类FutureTask的对象(用来管理多线程运行的结果) 5.创建Thread类的对象,并启动(表示线程)
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread().getName());
return "hello callable!";
}
}
public class ThreadDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/**
* 多线程第三种实现方式
* 特点:可以获取多线程运行结果
* 1.创建一个MyCallable类实现Callable接口
* 2.重写call方法(有返回值,表示多线程运行的结果)
*
* 3.创建MyCallable类对象(表示多线程要执行的任务)
* 4.创建Future接口的实现类FutureTask的对象(用来管理多线程运行的结果)
* 5.创建Thread类的对象,并启动(表示线程)
*/
//创建MyCallable类对象(表示多线程要执行的任务)
MyCallable my=new MyCallable();
//用futureTask去管理多线程运行的结果
FutureTask<String> futureTask=new FutureTask<>(my);
//创建Thread类的对象,并启动(表示线程)
new Thread(futureTask).start();
//获取多线程运行的结果并打印
String result = futureTask.get();
System.out.println(result);
}
}
三、线程中常见的成员方法
代码演示:
1.获取线程名称、设置线程名、获取当前线程对象与休眠指定线程:
public class MyThread extends Thread {
public MyThread() {
}
public MyThread( String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"@"+i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
/*
1 setName(String name)
如果没有给线程设置名字,线程默认名字格式:Thread-X(X为序号,从0开始)
设置名称:1.setName(),2.构造方法也可以为线程起名
2 currentThread()获取当前线程对象
JVM启动后,会自动启动多条线程
其中有一条线程叫main线程,调用main方法并执行里面的代码
我们之前写的所有代码,都是运行在main线程中
3 sleep(Long time)让线程休眠指定时间,单位为毫秒
哪条线程执行到这个方法,哪条线程就会在这里停留指定时间
方法的参数:睡眠时间,单位:毫秒
1s=1000ms
当时间到了之后,线程会自动醒来,执行下面其他代码
*/
//1.创建线程对象
MyThread t1=new MyThread("线程1");
MyThread t2=new MyThread("线程2");
//2.开启线程
t1.start();
//Thread.sleep(1000);
t2.start();
}
}
2.设置线程优先级与获取线程优先级:
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName()+"_"+i);
}
}
}
public class ThreadMethod {
public static void main(String[] args) {
/*
* setPriority(int newPriority);设置线程优先级
* 优先级从1到10,优先级越高抢占cpu执行权概率越大
* 优先级默认为5
* final int getPriority();获取线程优先级
* */
//创建线程要执行的任务
MyRunnable mr=new MyRunnable();
//创建线程对象,执行任务
Thread t1=new Thread(mr,"线程1");
Thread t2=new Thread(mr,"线程2");
//查看线程优先级 5
System.out.println(t1.getPriority());
System.out.println(t2.getPriority());
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
}
}
3.设置守护线程:守护线程会在其他线程执行完毕后延迟结束。
public class DaemonThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"+"+i);
}
}
}
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i <=10; i++) {
System.out.println(getName()+"_"+i);
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
/**
* final void setDemo(boolean on) 设置为守护线程
* 当其他的非守护线程执行完毕后,守护线程会陆续草草收尾(不会马上结束)
* 通俗:
* 女神结婚了,备胎没有存在的必要了
* 应用场景:
* QQ聊天时,聊天窗口会占据一个线程,文件传输也会有一个线程
* 当文件正在传输,聊天窗口关闭,文件传输也会停止
*/
MyThread t1=new MyThread();
DaemonThread t2=new DaemonThread();
t1.setName("女神");
t2.setName("备胎");
//设置守护线程(备胎线程)
t2.setDaemon(true);
t1.start();
t2.start();
}
}
4.出让线程/礼让线程
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"@"+i);
//表示让出当先cpu的执行权
Thread.yield();
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
/**
* public static void yield() 出让线程/礼让线程
* 当线程1抢到cpu执行权后让出执行权给其他线程
* 尽可能让线程的执行更加均匀
*/
MyThread t1=new MyThread();
MyThread t2=new MyThread();
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();
}
}
5.插入线程/插队线程 :把指定线程插到当前线程之前执行
public class myThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+"@"+i);
}
}
}
public class ThreadDemo {
/**
* public final void join() 插入线程/插队线程
*
*/
public static void main(String[] args) throws InterruptedException {
myThread t=new myThread();
t.setName("土豆");
t.start();
//把土豆线程插入到当前线程之前 当前线程:main线程
t.join();
//执行main线程中
for (int i = 0; i < 10; i++) {
System.out.println("main线程"+i);
}
}
}