合肥公司建设网站制作,网上设计接单赚钱,seo免费工具,小组做数据库网站目录
线程
什么是线程
进程和线程的区别
线程的生命周期
什么是多线程
并发与并行
多线程的三种实现方式
继承Thread类
1.创建类继承Thread类
2.重写run#xff08;#xff09;方法
3.创建对象启动线程
实现Runnable接口
1.自己定义一个类实现Runnable接口
2.重…目录
线程
什么是线程
进程和线程的区别
线程的生命周期
什么是多线程
并发与并行
多线程的三种实现方式
继承Thread类
1.创建类继承Thread类
2.重写run方法
3.创建对象启动线程
实现Runnable接口
1.自己定义一个类实现Runnable接口
2.重写run方法
3.创建自己类的对象
4.创建一个Thread类的对象并开启线程
实现Callable接口与FutureTask类
1.实现Callable接口
2.重写call方法并return线程执行的结果
3.创建Callable对象
4.把Callable对象封装成FutureTask对象
5.把任务交给Thread类
6.获取执行的结果
Thread常用方法
Thread常用构造器
为什么启动线程要调用start方法而不是直接调run方法
线程安全
线程同步
思想
常见方案
同步代码块
作用
原理
锁对象的使用规范
同步方法
作用
底层原理
Lock锁
线程通信
什么是线程通信
生产者与消费者模型
等待和唤醒方法
线程池
什么是线程池
不使用线程池的问题
线程池组成
线程池参数
线程池执行任务的流程
临时线程什么时候创建
什么时候会拒绝新任务 线程
什么是线程
线程是操作系统能够进行运算调度的最小单位它被包含在进程之中是进程中的实际运作单位。 进程进程是程序执行的基本实体。 拿任务管理器来举例 我们可以看到其中的Edge、火绒等等这些应用程序我们就可以理解为他们是电脑里面的一个个进程。而在Edge中有九个就是在Edge这个进程里面对应的线程。 进程和线程的区别
根本区别进程是操作系统资源分配的基本单位而线程是处理器任务调度和执行的基本单位
资源开销每个进程都有独立的代码和数据空间程序上下文程序之间的切换会有较大的开销线程可以看做轻量级的进程同一类线程共享代码和数据空间每个线程都有自己独立的运行栈和程序计数器PC线程之间切换的开销小。
包含关系如果一个进程内有多个线程则执行过程不是一条线的而是多条线线程共同完成的线程是进程的一部分所以线程也被称为轻权进程或者轻量级进程。
内存分配同一进程的线程共享本进程的地址空间和资源而进程之间的地址空间和资源是相互独立的
影响关系一个进程崩溃后在保护模式下不会对其他进程产生影响但是一个线程崩溃整个进程都死掉。所以多进程要比多线程健壮。
执行过程每个独立的进程有程序运行的入口. 顺序执行序列和程序出口。但是线程不能独立执行必须依存在应用程序中由应用程序提供多个线程执行控制两者均可并发执行。
线程的生命周期
一个线程大致上有六种状态。
New新建new Thread()出来的就是新建状态。
Runnable可运行新建线程调用start方法。
Teminated被终止线程执行完毕或者异常进入终止状态。
Blocked锁阻塞当线程没有得到锁的时候便会进入锁阻塞状态比如说a线程再访问一个需要锁的资源时b线程也来访问由于无法获得锁便会进入锁阻塞状态等到a线程释放锁之后b线程拿到锁便会回到Runnable可运行状态。
Waiting无限等待当a线程对象使用wait方法之后会进入无限等待状态只有其他线程比如b线程使用notify唤醒了a线程如果a线程没有锁进入锁阻塞状态如果有锁回到Runnable状态。
Timed Waiting计时等待当线程从Runnable状态调用sleep毫秒或者wait毫秒之后会进入计时等待时间结束之后。
回到Runnable
sleep时间到。 pssleep状态不会释放锁而wait状态会释放锁。wait时间到并得到锁对象。wait时间没到被其他线程notify并得到锁对象
进入Blocked
wait时间到或者被notify未获得锁对象。 什么是多线程
在一个进程中同时执行多个线程的编程模型。线程是程序执行的最小单元多线程编程允许程序在同一进程中的多个线程中并发执行从而实现并行处理和提高系统的性能。
在多线程编程中多个线程可以在同一时间片内交替执行每个线程都有自己的执行路径和执行状态。不同于单线程程序只能按照顺序一步一步地执行多线程程序可以同时执行多个任务从而提高了并发性和响应性。
并发与并行
并发在同一时刻有多个指令在单个cpu上交替执行。
并行在同一时刻有多个指令在多个cpu上同时执行。
多线程的三种实现方式
继承Thread类
1.创建类继承Thread类
2.重写run方法
package JUCDemo.demo1;
public class myThread extends Thread{Overridepublic void run() {for (int i 0;i 10;i ){System.out.println(getName() Hello Thread);}}
}3.创建对象启动线程
package JUCDemo.demo1;
public class demo1 {public static void main(String[] args) {/*1.定义一个类继承Thread类2.重写Run方法3.创建子类对象并启动线程*/myThread t1 new myThread();myThread t2 new myThread();myThread t3 new myThread();t1.setName(t1);t2.setName(t2);t3.setName(t3);t1.start();t2.start();t3.start();}
}优点编写简单如果需要访问当前线程则无需使用Thread.currentThread()方法直接使用this即可获得当前线程。
缺点线程类已经继承了Thread类所以不能再继承其他父类。
实现Runnable接口
1.自己定义一个类实现Runnable接口
2.重写run方法
package JUCDemo.demo2;
public class myRunnable implements Runnable{Overridepublic void run() {//获取当前线程的对象Thread t Thread.currentThread();for (int i 0; i 10; i) {System.out.println(t.getName()线程执行);}}
} 3.创建自己类的对象
4.创建一个Thread类的对象并开启线程
package JUCDemo.demo2;
public class demo2 {public static void main(String[] args) {myRunnable myRunnable new myRunnable();Thread t1 new Thread(myRunnable);Thread t2 new Thread(myRunnable);t1.setName(t1);t2.setName(t2);t1.start();t2.start();}
}优点没有继承Thread类所以可以继承其他的类适合多线程访问同一资源的情况将cpu和数据分开形成清晰的模型较好的体现了面向对象的思想
缺点编程相对复杂要想获得当前线程对象需要使用Thread.currentThread()方法。
实现Callable接口与FutureTask类
1.实现Callable接口
其中我们要制定返回的参数值类型这里使用String。
2.重写call方法并return线程执行的结果
package JUCDemo.demo3;
import java.util.concurrent.Callable;
//1.实现Callable接口
public class myCallable implements CallableString {int n 0;public myCallable(int n) {this.n n;}//2.重写Call方法Overridepublic String call() throws Exception {int sum 0;for (int i 0; i n; i) {sum sum i;}return 线程执行1到 n 的和是: sum;}
}
3.创建Callable对象
4.把Callable对象封装成FutureTask对象
FutureTask
由于Callable对象是无法扔给Thread的所以我们要通过封装成FutureTask对象的形式把我们的Callable对象交给Thread。 我们通过FutureTask的源码可以发现他是实现了Runnable接口的。
5.把任务交给Thread类
6.获取执行的结果
package JUCDemo.demo3;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class demo {public static void main(String[] args) throws ExecutionException, InterruptedException {//3.创建Callable对象CallableString callable new myCallable(100);//4.把Callable对象封装成一个FutureTask对象任务对象//FutureTask的作用// 是一个任务对象实现了Runnable接口// 可以在任务结束之后调用get方法获取执行完毕的结果FutureTaskString f1 new FutureTask(callable);//5.把任务对象交给Thread对象new Thread(f1).start();//6.获取线程执行完毕的结果String rs f1.get();System.out.println(rs);}
}优点
线程任务类只是实现接口可以继续继承类和实现接口扩展性强。可以在线程执行完毕后去获得线程执行完毕的结果。
缺点
编码复杂。
Thread常用方法
Thread提供常用方法说明pulic void run()线程的任务方法public void start()启动线程public String getName()获取当前线程的名称默认是Thread-索引public void setName(String name)为线程设置名字public static Thread currentThread()获取当前执行的线程对象public static void sleeplong time让线程休眠public final void join调用当前这个方法让线程先执行完
Thread常用构造器
Thread常用构造器说明public ThreadString name可以为当前线程指定名称public ThreadRunnable target封装Runnable对象为线程对象public Thread Runnable targetString name封装Runnable对象为线程对象指定名称
为什么启动线程要调用start方法而不是直接调run方法
new 一个 Thread线程进入了新建状态; 调用start() 会执行线程的相应准备工作然后自动执行 run() 方法的内容调用 start() 方法会启动一个线程并使线程进入了就绪状态当分配到时间片后就可以开始运行了。这是真正的多线程工作。直接执行 run() 方法会把 run 方法当成一个 main 线程下的普通方法去执行并不会在某个线程中执行它所以这并不是多线程工作。 调用 start 方法方可启动线程并使线程进入就绪状态而 run 方法只是 thread 的一个普通方法调用还是在主线程里执行。
线程安全
Java线程安全问题是指在多线程环境下多个线程同时访问共享资源时可能导致的数据不一致、数据损坏或程序异常等问题。这种问题可能发生在并发读写共享变量、共享数据结构或共享资源的情况下。
举个栗子小明和小红共有一个银行账户里面有100块钱。
当小明和小红都执行取钱操作的时候系统会创建两个线程分别给小明和小红。
取钱分为两步第一步判断余额第二步账号减少余额并取出100。
当小明的线程判断完余额100但是没有执行减少余额这个步骤时小红线程进行了余额判断那么系统便会分别给小明和小红100这就是线程安全问题。
解决线程安全一般有三个方法分别是
线程同步
思想
让多个线程实现先后依次访问共享资源这样就解决了线程安全问题。
常见方案
加锁每次只允许一个线程加锁加锁之后才能访问共享资源访问完毕之后释放锁然后其他线程才能再进行加锁操作并访问共享资源。
即小明这个线程进入判断余额操作之后会对判断余额上一把锁上锁时小红线程就无法进行判断余额操作进入等待状态只有当小明取钱完毕后小红才能进行余额判断。
同步代码块
作用
使用synchronized关键字把共享资源的核心代码块上锁以保证此线程的安全。 原理
每次只允许一个线程加锁后进入执行完毕后自动解锁其他线程才可以进来执行。
锁对象的使用规范
建议使用共享资源作为锁对象对于实例方法建议this作为锁对象。对于静态方法建议使用字节码类名.class对象作为锁对象。
同步方法
作用
使用synchronized关键字把共享资源的核心方法上锁以保证此线程的安全。 底层原理
同步方法也是有隐藏式锁对象的只是锁的范围是整个方法代码。如果方法时实例方法同步方法默认this作为锁对象。如果方法时静态方法同步方法默认类名.class作为锁的对象。
Lock锁
Lock锁时jdk5开始提供的一个新的锁定操作通过它可以创建出锁对象来进行加锁和解锁更灵活、更强大、更方便。Lock是接口不能直接实例化需要使用它的实现类ReentrantLock来构建Lock锁对象。 线程通信
什么是线程通信
当多个线程共同操作共享的资源时线程之间通过某种方式互相告知自己的状态以相互协调避免无效的资源争夺。
生产者与消费者模型
生产者线程负责生产数据。
消费者线程负责消费生产者线程生产的数据。
生产者生产完数据应该等待自己通知消费者消费。消费者消费完数据也应该等待自己再通知生产者生产。
等待和唤醒方法
方法名称说明void wait()让当前线程等待并释放所占锁知道另一个线程调用notify方法或notifyAll方法void notify()唤醒正在等待的单个线程void notifyAll()唤醒所有正在等待的线程
线程池
什么是线程池
线程池就是一个可以复用线程的技术。
不使用线程池的问题
用户每发起一个请求后台就要创建一个新线程来处理下次新任务来了肯定又要创建新的线程来处理而创建新的线程的开销是很大的并且请求过多时肯定会产生大量线程出来这样会严重影响系统的性能。
线程池组成
线程池管理器ThreadPoolExecutor线程池管理器是线程池的核心组件负责创建、管理和调度线程。工作线程WorkQueue工作队列用于存储等待执行的任务。当有新的任务提交给线程池时线程池将任务放入工作队列中并由线程池中的线程按照一定的策略从队列中取出任务进行执行。线程池线程Worker Thread线程池中的线程是执行任务的工作单元。任务队列中的线程对象必须是实现了Runnable接口或者Callable接口的才能进入任务对列。
线程池参数
参数一corePoolSize指定线程池的核心线程数量。参数二maxmumPollSize指定线程池的最大线程数量。参数三keepAliveTime指定临时线程存活时间。参数四unit指定临时线程的存活时间单位。参数五workQueue指定线程池的任务对列。参数六threadFactory指定线程池的线程工厂。参数七handler指定线程池的任务拒绝策略。
可以理解成一个公司corePoolSize就是正式工数量maxmumPollSize就是最大员工数量正式工临时工keepAliveTime是临时工多长时间后会被辞退workQueue客人排队的地方。
线程池执行任务的流程 临时线程什么时候创建
核心线程在忙而且任务队列也满了。
什么时候会拒绝新任务
核心线程和临时线程都在忙任务队列也满了。