java第八章线程

文章目录

8.1线程概述

在这里插入图片描述

程序、进程、线程

一组静态代码
在这里插入图片描述
当程序获得cpu计算资源是不叫程序了,叫进程,动态的
是永远有资源的单位
在这里插入图片描述
就是一个执行机构
线程:进程,多对一
在这里插入图片描述
对应关系:
进程是分配的独立单位
线程是调度执行的独立单位
线程执行进程的任务,进程提供资源,组合起来完成任务
在这里插入图片描述
进程和线城是动态的,进程是拥有资源的单位,作为线程的后盾,线程来执行
相同一件事情,分的越多,并发,执行效率更高 ,也就是多线程
在这里插入图片描述
在java中对线程也进行了封装,class
在这里插入图片描述
id name 优先级(cpu调度)
在这里插入图片描述在这里插入图片描述在这里插入图片描述

多线程含义

main是主线程
会创建主线程
在这里插入图片描述
模拟QQ聊天和上传(实际上还是串行,但很快,就像并行)

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
实际都是主线程进行的:,根本没并行啊,
在这里插入图片描述

希望聊天单独生成一个线程,用户角度就并行了
用继承创建一个自己的新进程类
在这里插入图片描述

在这里插入图片描述
重写方法run,要进行什么都写到run里
在这里插入图片描述
下一步在创建聊天线程,并run(执行)
在这里插入图片描述
失败了:
在这里插入图片描述
不要使用run方法,线程执行时会自动调用,要好多事情呢(资源分配。。。。。)
调用的话,就是普通调用普通方法
启动线程:在这里插入图片描述
效果:(默认名)在这里插入图片描述
重置名字:所有属性都要在 start之前完成:
在这里插入图片描述
上传线程同理:在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述
ONE文件夹下

package one;

public class Qq {
    public Qq() {
    }

    public void LT() {
    }

    public void SC() {
    }

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        new Qq();
        LTThread ltThread = new LTThread();
        ltThread.setName("����");
        ltThread.start();
        SCThread scThread = new SCThread();
        scThread.setName("�ϴ�");
        scThread.start();
    }
}

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package one;

public class Test1 {
    public Test1() {
    }

    public static void main(String[] args) {
        System.out.println("我是测试程序");
        System.out.println(Thread.currentThread().getId());
        System.out.println(Thread.currentThread().getName());
        System.out.println(Thread.currentThread().getPriority());
    }
}

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package one;

public class SCThread extends Thread {
    public SCThread() {
    }

    public void run() {
        for(int i = 1; i < 101; ++i) {
            System.out.println(Thread.currentThread().getName() + ":上传进行进度" + i + "%");
        }

    }
}

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package one;

public class LTThread extends Thread {
    public LTThread() {
    }

    public void run() {
        for(int i = 1; i < 101; ++i) {
            System.out.println(Thread.currentThread().getName() + ":��������" + i + "%");
        }

    }
}

在这里插入图片描述

8.2线程的创建

不管是继承还是实现创建,在实例化时都可以塞到Thread tread =new Tread(a,“name”)里实现变量共享(如下链接举例)

总结的很好
在这里插入图片描述

继承Thread创建

在这里插入图片描述
线程创建时相关接口与具体类:
在这里插入图片描述
在这里插入图片描述
上节的做法
在这里插入图片描述

一定要重写run方法:

在这里插入图片描述
测试:new时未创建,只是实例化一个对象,start时才启动(分配资源,创建线程,执行)
启动两次?:异常:只能启动一次
还可以设置各种属性:但要在启动之前,
优先级:在java虚拟机中的优先策略,但在cpu中还会自己参考着重新考虑吧
在这里插入图片描述
还可以重搞构造方法:(不能重搞,但可继承)在这里插入图片描述
还可获取当前线程的属性:
两个写法,效果一样:
在这里插入图片描述

实现接口:Runnable创建

也没啥区别,就是主类 实例化那里注意下
在这里插入图片描述
在这里插入图片描述

只要是线程就必须实现接口,实现run方法

在这里插入图片描述

实现所有方法,但只有run方法

只实现了接口,没有start方法,要运行就要先封装
在这里插入图片描述
测试类

封装

在这里插入图片描述

在这里插入图片描述
名字是new
在这里插入图片描述

好处:创建相同对象,共享类中变量,但此时不同步

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

共享(t2,t3中的a不同)

new的a从100开始,new1的a也从100开始
在这里插入图片描述

共享静态变量,即可同步

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Callable和Future创建

很少用,没讲
在这里插入图片描述
Callable,call方法有个返回值

在这里插入图片描述

用future接口取返回值:
RunnableFuture同时符合两个
所以用FutrueTask

在这里插入图片描述
V是泛型在这里插入图片描述
要实现抽象方法call
在这里插入图片描述
在这里插入图片描述
一个接口实现一个接口,又实现一个接口(向上套娃)
在这里插入图片描述

先实现接口,并实现方法重写,

在这里插入图片描述

10:创建工具类,并从t3中取得call方法的值,实现了相应线程的接口
11:实现接口,封装
12:执行

在这里插入图片描述
在这里插入图片描述

可以获取返回值,可能等待较长出现异常

下图中的return
在这里插入图片描述

用get获取

在这里插入图片描述

法一 try catch

在这里插入图片描述

法二:抛出

在这里插入图片描述在这里插入图片描述

summary

在这里插入图片描述

一些特殊创建写法 比较

java是单继承的,使用继承的方式,就无法继承其他类了,继承层次就会很深,但接口可以多重,工程中实现接口的会比较多
在这里插入图片描述

匿名内部类

在这里插入图片描述
UI界面开发有可能会用
在这里插入图片描述

类的匿名

在这里插入图片描述
在这里插入图片描述

接口匿名实现

Thread()中间写接口
在这里插入图片描述

lambda表达式创建线程

在这里插入图片描述

线程里接受一个函数表达式

在这里插入图片描述

常见方法
测试类直接继承线程(一般用来测试)

在这里插入图片描述

测试类直接实现接口(一般用来测试)

在这里插入图片描述

8.3线程生命周期

在这里插入图片描述

8.3.1生命周期描述

进程拥有资源,执行调度
线程执行过程,有状态转换

新建状态:实例化
就绪状态:创建了线程、得到了资源,得到了除了cpu的所有资源
运行状态:在cpu中运行。(单核只能有一个)
分支:阻塞状态:除了cpu还缺其他资源,不能进行,所以就先失去cpu给别人,你先等着(比如缺打印机)
分支:DEAD:异常了、完成了、人为停止
分支:回就绪状态:听从cpu调度

在这里插入图片描述

8.3.2Thread常用方法(怎么实现上图)

线程类提供的常用方法

启动

在这里插入图片描述
并不是立即执行
在这里插入图片描述
在这里插入图片描述

让步方法

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
并发
在这里插入图片描述

只让出一次cpu

在这里插入图片描述
在这里插入图片描述

休眠,暂停

在这里插入图片描述
在这里插入图片描述
自动休眠与阻塞
在这里插入图片描述

可能会产生异常,

在这里插入图片描述

没有返回值不能抛出,只能try catch

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

等待线程结束

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
主线程先结束了,不合逻辑
在这里插入图片描述
这里用了抛出异常
thrad执行完,才能往下执行
在这里插入图片描述

成对,阻塞,需要同步问题,到时讲

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.4线程同步

在这里插入图片描述
进程是资源的后盾
线程是调度的单位
在这里插入图片描述
Java线程是共享进程中的资源
创建副本
在这里插入图片描述
比如A和B都想进行加1操作,原为3,A先将3拷贝,突然失去cpu,B拷贝+1,变4,将4 回写 到变量1,A重获的cpu,副本3+1回写4
最终变量一为4,可希望为5

在这里插入图片描述
引出问题:线程同步
在这里插入图片描述
第一种解决方案:

线程同步-可见性(非线程安全)

在这里插入图片描述
1.立刻
2.强制
3.是所有缓存了该变量的线程中的数据清空
在这里插入图片描述

可见性:有人改了,其他线程也该知道

在这里插入图片描述
验证:
由stop决定是否结束:()用环境变量达到同样的效果在这里插入图片描述在这里插入图片描述
修改:修改为真:
在这里插入图片描述
检测是否为共享变量(主线程,与testVo)
在这里插入图片描述
法二:让主线程休息2秒再修改:
在这里插入图片描述
不结束了,因为副本已经建立起来了,没通知修改,不可见
在这里插入图片描述

关键字的使用

在这里插入图片描述
在这里插入图片描述

线程同步-原子性问题

之前没解决()
还是都进行a+1操作
这些指令是可以中断的
中断时要保护线程,恢复是要恢复
希望不可被中断
在这里插入图片描述
在这里插入图片描述
锁机制:
在这里插入图片描述
区别在锁的类型:
在这里插入图片描述
测试:
看看执行f1的线程是谁,并休眠他
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
希望f1()同时只能被一个访问
想访问f1得先有锁
在这里插入图片描述
向t对象要锁
在这里插入图片描述
tt对象和t对象独立

另:多个线程共同执行同一个方法的情况,线程与runnnable对象

tt也在使用f1
t1 执行f1,向t要锁
t2也想要t的锁,等待
t3向tt要锁,所以可以执行
刚才是锁住同一个对象

在这里插入图片描述
如果对静态方法上锁,那就是整个类的锁
执行时,向类要锁
在这里插入图片描述
保证没有任何线程干扰
在这里插入图片描述
也不是特别公平
方法内有些代码不用锁
在这里插入图片描述
这句话就不用
所以用方法块
这样就不知道对类还是对象获取了
在这里插入图片描述
加上本对象要锁

在这里插入图片描述
对t1,t2 互斥
在这里插入图片描述
在这里插入图片描述
以类获取锁
在这里插入图片描述
也是以对象获锁,因为同一个对象内的成员对象才相同
在这里插入图片描述
这样就是类了(t,tt中的object相同)
在这里插入图片描述
在这里插入图片描述

lock接口

新的锁机制
在这里插入图片描述
在这里插入图片描述
实现类
在这里插入图片描述
区别:人为释放,finally中释放
在这里插入图片描述
老例子了:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
要先建立锁对象
在这里插入图片描述
上锁:
try:
finally
还锁:
在这里插入图片描述
在这里插入图片描述

wait()和notify()

阻塞方法,和唤醒方法

(sleep是自动唤醒)
wait是被动唤醒

在这里插入图片描述
由object提供

在这里插入图片描述
测试类:
新建一个线程,休眠两秒,继续执行
在这里插入图片描述
在搞一个一样的

在这里插入图片描述在这里插入图片描述
希望一个工作时另一个等待
互斥访问
想到同步代码块
每个都加上同步锁
在这里插入图片描述
对同一对象获取锁
在这里插入图片描述
两个都是

在这里插入图片描述
在这里插入图片描述
希望线程一执行-》停止-》二执行-》结束-》线程一

sleep休眠不放弃锁
wait放弃锁

在这里插入图片描述
线程1(thread0)一直在阻塞
在这里插入图片描述
线程2结束时唤醒1
在这里插入图片描述
在这里插入图片描述

区别

obj指上锁的那个对象
在这里插入图片描述

8.5线程池

在这里插入图片描述
GC:垃圾回收线程
在这里插入图片描述

线程池的概念

整体管理线程的机制,把握创建线程的度
在这里插入图片描述
core核心线程池:不能停
其他不工作就撤
没申请到就异常
在这里插入图片描述
在这里插入图片描述
有的不销毁,重新用
在这里插入图片描述

线程池相关类

在这里插入图片描述
四个构造方法
在这里插入图片描述
第一个参数:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
简单线程池类
在这里插入图片描述
肥宅憨憨池
在这里插入图片描述
会有返回值:
在这里插入图片描述
交给她管理
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
搞五个
在这里插入图片描述
在这里插入图片描述
max为5,(效果不太好,任务太短了)
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

这个例子是不是太好了???,难道不会有重复的id嘛

不是id的问题
name也会
A1:me:那他是先都加入到线程池然后执行的嘛 都在线程池中
me:啊,那就是说5个时,先往里加,然后在线程池里执行,10个的时候,先加5个,等有执行完了,再往里加,然后10个的那个重了好几次,就是有后加进去的先执行完了
A2:线程池线程复用原理

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
    public static void main(String[] args) {
       // System.out.println(121212)
        ExecutorService executorService =  Executors.newFixedThreadPool(5);
        for (int i=0;i<10;i++)
        {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
}

eg
pool-1-thread-5
pool-1-thread-4
pool-1-thread-3
pool-1-thread-1
pool-1-thread-5
pool-1-thread-1
pool-1-thread-5
pool-1-thread-2
pool-1-thread-5
pool-1-thread-1
A1:应该是对的:我尝试睡几秒,睡前睡后分开输出,但一开始的5个都没有线程被让出:

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
       // System.out.println(121212)
        ExecutorService executorService =  Executors.newFixedThreadPool(5);
        for (int i=0;i<10;i++)
        {
            executorService.submit(new Runnable() {

                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"开啦");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName()+"停啦error");
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"停啦2");
                }

            });
        }
    }
}

output:
pool-1-thread-2开啦
pool-1-thread-3开啦
pool-1-thread-4开啦
pool-1-thread-5开啦
pool-1-thread-1开啦


pool-1-thread-2停啦2
pool-1-thread-4停啦2

pool-1-thread-2开啦
pool-1-thread-4开啦

pool-1-thread-5停啦2
pool-1-thread-1停啦2
pool-1-thread-5开啦
pool-1-thread-3停啦2
pool-1-thread-1开啦
pool-1-thread-3开啦
pool-1-thread-4停啦2
pool-1-thread-3停啦2
pool-1-thread-1停啦2
pool-1-thread-5停啦2
pool-1-thread-2停啦2

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
       // System.out.println(121212)
        ExecutorService executorService =  Executors.newFixedThreadPool(5);
        for (int i=0;i<5;i++)
        {
            executorService.submit(new Runnable() {

                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"开啦");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName()+"停啦error");
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"停啦2");
                }

            });
        }
    }
}

pool-1-thread-1开啦
pool-1-thread-3开啦
pool-1-thread-2开啦
pool-1-thread-5开啦
pool-1-thread-4开啦


pool-1-thread-5停啦2
pool-1-thread-1停啦2
pool-1-thread-4停啦2
pool-1-thread-3停啦2
pool-1-thread-2停啦2

更诡异的情况:
本想看看(这样发现,是一起加进去的,但等着)

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
       // System.out.println(121212)
        ExecutorService executorService =  Executors.newFixedThreadPool(5);
        for (int i=0;i<10;i++)
        {
            System.out.println(" thisloop:"+i);
            executorService.submit(new Runnable() {

                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"开啦");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName()+"停啦error");
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"停啦2");
                }

            });
        }
    }
}

thisloop:0
thisloop:1
thisloop:2
thisloop:3
thisloop:4
thisloop:5
thisloop:6
thisloop:7
thisloop:8
thisloop:9


pool-1-thread-4开啦
pool-1-thread-3开啦
pool-1-thread-1开啦
pool-1-thread-2开啦
pool-1-thread-5开啦


pool-1-thread-3停啦2
pool-1-thread-4停啦2
pool-1-thread-1停啦2
pool-1-thread-2停啦2

pool-1-thread-4开啦
pool-1-thread-2开啦
pool-1-thread-5停啦2
pool-1-thread-5开啦
pool-1-thread-3开啦
pool-1-thread-1开啦
pool-1-thread-4停啦2
pool-1-thread-2停啦2
pool-1-thread-5停啦2
pool-1-thread-1停啦2
pool-1-thread-3停啦2

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
       // System.out.println(121212)
        ExecutorService executorService =  Executors.newFixedThreadPool(5);
        for (int i=0;i<10;i++)
        {
            System.out.println(Thread.currentThread().getName()+" thisloop:"+i);
            executorService.submit(new Runnable() {

                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"开啦");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName()+"停啦error");
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"停啦2");
                }

            });
        }
    }
}

误会,是巧合,,,,,,(我以为加上crrunentThread后就五个一起开一起关了呢)
out1

main thisloop:0
main thisloop:1
main thisloop:2
main thisloop:3
main thisloop:4
main thisloop:5
main thisloop:6
main thisloop:7
main thisloop:8
main thisloop:9
pool-1-thread-3开啦
pool-1-thread-4开啦
pool-1-thread-2开啦
pool-1-thread-5开啦
pool-1-thread-1开啦
pool-1-thread-2停啦2
pool-1-thread-1停啦2
pool-1-thread-4停啦2
pool-1-thread-3停啦2
pool-1-thread-5停啦2
pool-1-thread-2开啦
pool-1-thread-3开啦
pool-1-thread-5开啦
pool-1-thread-4开啦
pool-1-thread-1开啦
pool-1-thread-2停啦2
pool-1-thread-5停啦2
pool-1-thread-3停啦2
pool-1-thread-4停啦2
pool-1-thread-1停啦2

out2
main thisloop:0
main thisloop:1
main thisloop:2
main thisloop:3
main thisloop:4
main thisloop:5
main thisloop:6
main thisloop:7
main thisloop:8
main thisloop:9
pool-1-thread-4开啦
pool-1-thread-2开啦
pool-1-thread-5开啦
pool-1-thread-1开啦
pool-1-thread-3开啦
pool-1-thread-2停啦2
pool-1-thread-2开啦
pool-1-thread-5停啦2
pool-1-thread-3停啦2
pool-1-thread-5开啦
pool-1-thread-4停啦2
pool-1-thread-4开啦
pool-1-thread-1停啦2
pool-1-thread-1开啦
pool-1-thread-3开啦
pool-1-thread-2停啦2
pool-1-thread-5停啦2
pool-1-thread-4停啦2
pool-1-thread-1停啦2
pool-1-thread-3停啦2

而且主线程和他们之间也有调度,都在池里?

main thisloop:0
main thisloop:1
main thisloop:2
main thisloop:3
main thisloop:4
main thisloop:5
main thisloop:6
main thisloop:7
main thisloop:8
pool-1-thread-1开啦
pool-1-thread-4开啦
pool-1-thread-2开啦
main thisloop:9
pool-1-thread-5开啦
pool-1-thread-3开啦
pool-1-thread-4停啦2
pool-1-thread-5停啦2
pool-1-thread-2停啦2
pool-1-thread-1停啦2
pool-1-thread-4开啦
pool-1-thread-3停啦2
pool-1-thread-3开啦
pool-1-thread-2开啦
pool-1-thread-1开啦
pool-1-thread-5开啦
pool-1-thread-4停啦2
pool-1-thread-3停啦2
pool-1-thread-1停啦2
pool-1-thread-5停啦2
pool-1-thread-2停啦2

当给主线程加上100ms等待:
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    public static void main(String[] args) {
       // System.out.println(121212)
        ExecutorService executorService =  Executors.newFixedThreadPool(5);
        for (int i=0;i<10;i++)
        {
            System.out.println(Thread.currentThread().getName()+" thisloop:"+i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            executorService.submit(new Runnable() {

                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"开啦");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName()+"停啦error");
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"停啦2");
                }

            });
        }
    }
}

main thisloop:0
main thisloop:1
pool-1-thread-1开啦
main thisloop:2
pool-1-thread-2开啦
main thisloop:3
pool-1-thread-3开啦
main thisloop:4
pool-1-thread-4开啦
main thisloop:5
pool-1-thread-5开啦
main thisloop:6
main thisloop:7
main thisloop:8
main thisloop:9
pool-1-thread-1停啦2
pool-1-thread-1开啦
pool-1-thread-2停啦2
pool-1-thread-2开啦
pool-1-thread-3停啦2
pool-1-thread-3开啦
pool-1-thread-4停啦2
pool-1-thread-4开啦
pool-1-thread-5停啦2
pool-1-thread-5开啦
pool-1-thread-1停啦2
pool-1-thread-2停啦2
pool-1-thread-3停啦2
pool-1-thread-4停啦2
pool-1-thread-5停啦2

intelliJ idea 使用try/catch 快捷提示

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值