当前位置 博文首页 > @王某人:java多线程

    @王某人:java多线程

    作者:[db:作者] 时间:2021-06-17 21:14

    线程与进程:

    ? ? ?进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间

    ? ? ?线程:每个线程都拥有自己的栈内存,公用一份堆内存是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行. 一个进程最少 有一个线程

    ? ? ?? ? ?线程实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分 成若干个线程

    线程调度:

    ? ? ? 分时调度:

    ? ? ? ? ? ? ? 所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。

    ? ? ? 抢占式调度:

    ? ? ? ? ? ?优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性), Java使用的为 抢占式调度。

    ? ? ? ? ? CPU使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核新而言,某个时刻, 只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是 在同一时 刻运行。 其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的 使 用率更高。

    同步与异步:

    ? ? ? ? 同步:排队执行 , 效率低但是安全.

    ? ? ? ? 异步:同时执行 , 效率高但是数据不安全

    并发与并行:

    ? ? ?并发:指两个或多个事件在同一个时间段内发生。

    ? ? ?并行:指两个或多个事件在同一时刻发生(同时发生)。

    在JAVA中实现多线程:

    1.继承Thread类

    重写run方法

    run方法就是要执行的线程方法

    里面编写的代码就是一条新的执行路径

    路径的触发方式不是调用run()方法,而是通过Thread对象的start方法来启动任务

    mythread m = new mythread();
    m.start();

    2.实现Runnable接口

    重写run方法,原理与上面相同

    myrunnable r = new myrunnable;    //创建一个任务
    Thread t = new Thread(r);         //创建一个线程,给他分配一个任务
    t.start();

    实现Runnable有如下优势:

    ? ? 1.采用创建任务的方式,给线程分配任务,适合多个线程执行同一任务的情况

    ? ? 2.可以避免单继承带来的局限性

    ? ? 3.任务与线程之间是分离的,提高了程序的健壮性

    ? ? 4.后续学习的线程池技术,接受Runnable任务,不接受Thread类型线程

    Thread类:

    ? ?构造方法:

    ? ? ? ??Thread()? ? ? ? ? 创建线程对象

    ? ? ? ??Thread(String name) ? ? ? ? ? 创建线程对象,并给个名字

    ? ? ? ??Thread?(Runnable?target) ? ? ? ? ? 创建一个线程,并分配一个任务

    ? ? ? ??Thread?(Runnable?target,String name) ? ? ? ? ? 分配一个任务,并给个名字

    ? 方法:

    ? ? ? ??sleep?(long?millis) ? ? ? ??使线程休眠(线程暂停的毫秒数)是静态方法

    ? ? ? ??sleep?(long?millis, int?nanos) ? ? ? ??线程休眠(线程暂停的毫秒数加纳秒数)

    ? ? ? ??getName()? ? ? ?? 获取线程的名字

    ? ? ? ??getId() ? ? ? ??获取线程的标识符

    ? ? ? ??setPriority?(int?newPriority) ? ? ? ??更改线程的优先级,参考字段

    ? ? ? ??getPriority() ? ? ? ??获得线程的优先级

    ? ? ? ??start() ? ? ? ??线程开始执行,虚拟机调用run()方法

    ? ? ? ??setDaemon?(boolean?on) ? ? ? ??将线程标记为守护线程或用户线程,true为守护

    ? ? ? ??currentThread() ? ? ? ??获取当前正在使用的线程,搭配getname方法

    ? ? ? ??interrupt() ? ? ? ??给线程添加中断标记

    线程阻塞(耗时操作):任何耗时的操作都可以理解为线程阻塞,例如:读取文件,接受用户输入

    线程中断:一个线程就是一个独立的执行路径,它是否应该结束,应该由他自身决定

    ? ? ? ? ? ? ? ? ? ?通过interrupt方法给线程添加标记,wait方法和sleep方法都会检查是否有中断标记

    ? ? ? ? ? ? ? ? ?会进入catch块,在catch块中输入return;结束线程,也可以在里面进行资源释放

    线程:分为守护线程和用户线程

    ? ? ? 用户线程;当一个进程不包含任何存活的用户线程时,进程结束

    ? ? ? ?守护线程:守护用户线程的,当最后一个用户线程结束时,守护线程自动结束

    线程安全问题:解决方案(加锁的方式)

    1.线程同步:synchronized(同步代码块)

    ? ?创建一个对象当做锁,每一个线程进来都检查这个锁是否上锁

    格式:synchronized(锁对象){}

    2.同步方法:

    将判断操作放到synchronized修饰的方法当中

    1,2都属于隐式锁

    3.显示锁 Lock 类的子类 ReentrantLock

    ? ? ? ?Lock lock = new ReentrantLock();

    在判断前加锁; lock.lock();

    解锁: lock.unlock();

    公平锁与非公平锁:

    公平锁:所有线程排队抢

    非公平锁:谁抢到是谁的(java默认)

    创建显示锁时传入True为公平锁

    线程通信:

    Object类的wait()和notify()唤醒方法, Object.notifyAll()

    Objecet.wait()

    线程的六种状态:

      • NEW

    尚未启动的线程处于此状态,线程刚被创建

      • RUNNABLE

    在Java虚拟机中执行的线程处于此状态。

      • BLOCKED

    被阻塞等待监视器锁定的线程处于此状态,线程排队时。

      • WAITING

    无限期等待另一个线程执行特定操作的线程处于此状态。

      • TIMED_WAITING

    正在等待另一个线程执行最多指定等待时间的操作的线程处于此状态。

      • TERMINATED

    已退出的线程处于此状态。

    带返回值的线程Callable:

    使用步骤:

    1. 编写类实现Callable接口 , 实现call方法

    class XXX implements Callable {

    ? ? @Override

    ? ? public call() throws Exception {

    ? ? ? ? ? return T;

    ? ?}

    }

    2. 创建FutureTask对象 , 并传入第一步编写的Callable类对象

    FutureTask future = new FutureTask<>(callable);

    3. 通过Thread,启动线程

    new Thread(future).start()

    Callable接口的call()允许抛出异常;Runnable的run()不能抛出

    方法:

    ? ? ?get() 获取线程返回值,但是主线程要等待子线程执行完毕,返回结果

    ? ? ?get?(long?timeout, TimeUnit?unit) 可以传入最多等待时间

    ? ? isDone() 判断线程是否执行完毕

    ? ? cancel(Boolean x ) 传入True是取消,返回False指任务执行完毕,不用取消

    线程池:

    如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建

    线程 就会大大降低 系统的效率,线程池就是一个容纳多个线程的容 器,池中的线程可以反复使

    用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。

    ?

    java中四种线程池:. ExecutorService

    缓存线程池:

    长度无限制

    流程: 1.判断线程池中是否有空闲线程

    2.有空闲则使用

    3.没有空闲则创建线程,并放入线程池中,然后使用

    ? ? ExecutorService service = Executors.newCachedThreadPool();

    ? ? //向线程池中 加入 新的任务

    ? ? service.execute(new Runnable() {

    ? ? ? ? @Override public void run() {

    ? ? ? ? ? ? System.out.println("线程的名称:"+Thread.currentThread().getName());

    ? ? ? ? }

    ? ? });

    定长线程池:

    ? ? ExecutorService service = Executors.newFixedThreadPool(2);

    ? ? service.execute(new Runnable() {

    ? ? ? ? @Override public void run() {

    ? ? ? ? System.out.println("线程的名称:"+Thread.currentThread().getName());

    ? ? ? ? }

    ? ? });

    单线程线程池:

    效果与定长线程池 创建时传入数值1 效果一致.

    ? ? ExecutorService service = Executors.newSingleThreadExecutor();

    ? ? ? ? service.execute(new Runnable() {

    ? ? ? ? ? ? @Override public void run() {

    ? ? ? ? System.out.println("线程的名称:"+Thread.currentThread().getName());

    ? ? ? ? }

    ? ? });

    周期定长线程池:

    定时执行

    参数1. runnable类型的任务

    参数2. 时长数字

    参数3. 时长数字的单位

    ? ? ScheduledExecutorService service = Executors.newScheduledThreadPool(2);

    ? ? ? ? service.schedule(new Runnable() {

    ? ? ? ? @Override public void run() {

    ? ? ? ? System.out.println("俩人相视一笑~ 嘿嘿嘿");

    ? ? }

    ? ? },5,TimeUnit.SECONDS);

    周期执行

    参数1. runnable类型的任务

    参数2. 时长数字(延迟执行的时长)

    参数3. 周期时长(每次执行的间隔时间)

    参数4. 时长数字的单位

    ? ? service.scheduleAtFixedRate(new Runnable() {

    ? ? ? ? @Override public void run() {

    ? ? ? ? ? ? System.out.println("俩人相视一笑~ 嘿嘿嘿");

    ? ? ? ? }

    ? ? },5,2,TimeUnit.SECONDS);

    Lambda表达式

    函数式编程思想

    接口只有一个抽象方法才可以使用Lambda表达式

    Thread t = new Thread(() -> System.out.println("锄禾日当午");)

    t.start();

    ?

    下一篇:没有了