多线程&JUC
1、多线程概述
线程
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位
简单理解:应用软件中互相独立,可以同时运行的功能
进程
进程是程序的基本执行实体(任务管理器中每个软件运行之后本身就是一个进程,是独立运行的程序)
一、进程和线程的区别
-
定义
-
进程:操作系统资源分配的最小单位,是独立运行的程序。
-
线程:进程内的执行单元,CPU 调度执行的最小单位,一个进程可包含多个线程。
-
-
资源
-
进程:拥有独立内存、资源,进程间互不共享。
-
线程:共享所在进程的内存与资源,仅栈、程序计数器私有。
-
-
开销
-
进程:创建、销毁、切换开销大。
-
线程:开销小,切换更快。
-
-
独立性
-
进程:相互独立,一个进程崩溃不影响其他进程。
-
线程:共享进程资源,一个线程异常,可能导致整个进程崩溃。
-
-
通信
-
进程间通信复杂;线程间共享数据,通信简单。
-
多线程的应用场景 同时可以执行多个不同的命令,同时做多个不同的事情
软件中的耗时操作 所有的聊天软件 所有的后台服务器
拷贝大文件 加载大量的资源文件
并发和并行
并发:在同一时刻,有多个指令在单个CPU上交替执行
并行:在同一时刻,有多个指令在多个CPU上同时执行
2、多线程的实现方式
多线程的实现方式
(1)继承Thread类的方式进行实现
(2)实现Runnable接口的方式进行实现
(3)利用Callable接口和Future接口方式实现
(1)第一种实现方式
Thread类其实就是一个线程
创建一个新线程方式:继承Thread类,该子类重写Thread类中的run方法。
/* '多线程的第一种启动方式: 1、自己定义一个类继承Thread 2、重写run方法 3、创建子类的对象,并启动线程 */
package Thread;
public class ThreadDemo1 {
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();
}
}
public class MyThread extends Thread{
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println(getName()+"HelloWorld");
}
}
}
(2)第二种实现方式
声明实现Runnable接口的类。实现run方法
/* 多线程的第二种启动方式: 1、自己定义一个类实现Runnable接口 2、重写里面的run方法 3、创建自己的类的对象 4、创建一个Thread类的对象,并开启线程 */
package Runnable;
public class RunnableDemo {
public static void main(String[] args) {
/*
多线程的第二种启动方式:
1、字节定义一个类实现Runnable接口
2、重写里面的run方法
3、创建自己的类的对象
4、创建一个Thread类的对象,并开启线程
*/
//创键MyRun表示多线程要执行的任务
MyRun mr = new MyRun();
//创建线程对象
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
//给线程设置名字
t1.setName("线程1");
t2.setName("线程2");
//开启线程
t1.start();
t2.start();
}
}
public class MyRun implements Runnable{
@Override
public void run() {
for(int i=0;i<10;i++){
//获取到当前线程的对象
// Thread t = Thread.currentThread();
// System.out.println(t.getName() + "HelloWorld");
System.out.println(Thread.currentThread().getName() + "HelloWorld");
}
}
}
(3)第三种实现方式
利用Callable接口和Future接口方式实现
/* 多线程的第三种实现方式 特点:可以获取到线程运行的结果 1、创建一个类MyCallable实现Callable(带泛型<>)接口 2、重写call方法(是有返回值的,表示多线程运行的结果) 3、创建MyCallable的对象(表示多线程要执行的任务) 4、创建FutureTask<数据类型>的对象(作用管理多线程运行的结果) */
package CallableAndFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableAndFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*
多线成的第三种实现方式
特点:可以获取到线程运行的结果
1、创建一个类MyCallable实现Callable接口
2、重写call方法(是有返回值的,表示多线程运行的结果)
3、创建MyCallable的对象(表示多线程要执行的任务)
4、创建FutureTask的对象(作用管理多线程运行的结果)
5、创建Thread类的对象,并启动(表示多线程)
*/
//创建MyCallable的对象(表示多线程要执行的任务)
MyCallable mc = new MyCallable();
//创建FutureTask的对象(作用管理多线程运行的结果)
FutureTask<Integer> ft = new FutureTask<>(mc);
//创建Thread类的对象,并启动(表示多线程)
Thread t1 = new Thread(ft);
t1.start();
//获取多线程运行的结果
Integer result = ft.get();
System.out.println(result);
}
}
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i=1;i<=100;i++){
sum+=i;
}
return sum;
}
}
(4)三种实现方式的对比及应用场景

如果使用第一种实现方式,因为java继承只能单继承,所以不能再继承其他类,扩展性差
如果想要得到线程结果,则使用第三种实现Callable和Future接口
3、多线程的常见成员方法
常见的成员方法
String getName() 返回此线程的名称void setName(String name) 设置线程的名字(构造方法也可以设置名字)staticThread currentThread() 获取当前线程的对象staticvoid sleep(long time) 让线程休眠指定的时间,单位为毫秒setPriotity(int newPriority) 设置线程的优先级final int getPriority() 获取线程的优先级final void setDaemon(boolean on) 设置守护线程public satic void yield() 出让线程/礼让线程public static void Join() 插入线程/插队线程
(1)简单方法
getName()和setName(String name)方法的细节:
1、如果我们没有给线程设置名字,线程也是有默认的名字的
格式:Thread-X(X序号,从0开始的)
2、如果我们要给线程设置名字,可以用set方法进行设置,也可以用构造方法设置
Static Thread currentThread() 获取当前线程的对象细节:
当JVM虚拟机启动后,会自动的启动多条线程
其中一条线程就叫做main线程
他的左作用就是去调用main方法,并执行里面的代码
在以前,我们写的所有的代码,其实都是运行在main线程当中
Static void sleep(long time) 让线程休眠指定的时间,单位为毫秒
package Threadmethod;
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
//构造方法设置线程名
MyThread t1 = new MyThread("神人");
MyThread t2 = new MyThread("人机");
//setName设置线程名
t1.setName("线程1");
t2.setName("线程2");
//开启线程
t1.start();
t2.start();
Thread t = Thread.currentThread();
System.out.println(t.getName());
//sleep暂停当前线程5秒钟,然后继续执行代码
System.out.println("111111111");
Thread.sleep(5000);
System.out.println("222222222");
}
}
public class MyThread extends Thread {
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(getName() + "@" + i);
}
}
}
(2)线程的优先级
抢占式调度
setPriotity(int newPriority) 设置线程的优先级参数为1-10Final int getPriority() 获取线程的优先级
注:优先级从1-10,默认是5,优先级越高抢占CPU概率大
public class Demo2 {
public static void main(String[] args) {
//创建线程要执行的参数对象
MyRun mr = new MyRun();
//创建线程对象
Thread t1 = new Thread(mr,"神人");
Thread t2 = new Thread(mr,"人机");
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
}
}
public class MyRun implements Runnable{
@Override
public void run() {
for(int i=0;i<=50;i++){
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
}
(3)设置守护线程
Final void setDaemon(boolean on) 设置守护线程
细节:
当其他的非守护线程执行完毕之后,守护线程会陆续结束
通俗易懂:
当女神线程执行完毕,备胎也没有存在的必要了,他们会陆陆续续去找其他女神,而并不是直接走掉
public class Demo3 {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
t1.setName("女神");
t2.setName("备胎");
//把第二个线程设置为守护线程
t2.setDaemon(true);
t1.start();
t2.start();
}
}
public class MyThread1 extends Thread {
@Override
public void run() {
for(int i=0;i<=10;i++){
System.out.println(getName()+"---"+i);
}
}
}
public class MyThread2 extends Thread {
@Override
public void run() {
for(int i=1;i<=100;i++){
System.out.println(getName() + "---" + i);
}
}
}
(4)礼让线程
Public satic void yield() 出让线程/礼让线程
作用:让不同线程执行结果尽可能均匀
Thread.yield()
是一个静态方法,作用是主动让出当前 CPU 的执行权,让调度器重新选择线程执行。
注意:它只是 “礼貌地礼让”,不保证其他线程一定能抢到执行权,也不保证自己立刻就能被调度回来。
package com.itheima.a07threadmethod4;
public class ThreadDemo {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("飞机");
t2.setName("坦克");
t1.start();
t2.start();
}
}
package com.itheima.a07threadmethod4;
public class MyThread extends Thread {
@Override
public void run() {
// "飞机" "坦克"
for (int i = 1; i <= 100; i++) {
System.out.println(getName() + "@" + i);
// 表示出让当前CPU的执行权
Thread.yield();
}
}
}
(5)插入线程
Public static void Join() 插入线程/插队线程
public class ThreadDemo {
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.setName("土豆");
t.start();
// 表示把t这个线程,插入到当前线程之前。
// t:土豆
// 当前线程: main线程
t.join();
// 执行在main线程当中的
for (int i = 0; i < 10; i++) {
System.out.println("main线程" + i);
}
}
}
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(getName() + "@" + i);
}
}
}
&spm=1001.2101.3001.5002&articleId=162234344&d=1&t=3&u=5b12722db4ef44dda449353b4e71adf2)
6万+

被折叠的 条评论
为什么被折叠?



