多线程(Java.Thread)学习(完结)

多线程(Java.Thread)学习

线程简介:

1、线程是独立执行的路径
2、程序运行时有很多后台进程 比如主线程、young.gc、full.gc()
3main是主线程,系统入口,用于执行整个程序
4、一个进程中、如果开辟多个线程,线程的运行由调度器安排调度、调度器的先后顺序不能人为干预
5、对同一份资源操作时,会存在资源抢夺问题,需要加入并发控制
6、线程会带来额外的开销,比如cpu调度时间,并发控制开销
7、每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

线程实现:

Thread

/**
 * @Description:TODO
 * @Author:Administrator
 * @Create 2024/1/12
 */
public class ThreadTest extends Thread{
    // 线程入口点
    @Override
    public void run() {
        // 线程体
        for (int i = 0;i<10;i++){
            System.out.println("我在看蒂法....."+i);
        }
    }
    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
            threadTest.start();//开启线程,不一定立即执行 需要cpu调度
            threadTest.run();//立即执行线程 
        for (int i =0;i<10;i++){
            System.out.println("我在学Java Thread"+i);
        }
    }
}

开启 Thread 线程 下载网图,验证start方法线程执行交给cpu。

public class ThreadTest2 extends Thread {
    private String url;
    private String name;

    public ThreadTest2(String url,String name){
        this.url = url;
        this.name =name;
    }
    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.download(url,name);
        System.out.println("下载了文件名为:"+name);
    }
    public static void main(String[] args) {
        ThreadTest2 threadTest1 = new ThreadTest2("https://aistyle.art/assets/files/2023-06-30/1688166112-995353-348703237-145251275241612-1956428239713994473-n.jpg","明日香1.jpg");
        ThreadTest2 threadTest2 = new ThreadTest2("https://bkimg.cdn.bcebos.com/pic/8b13632762d0f703918fecd9c0b1463d269759ee6f28?x-bce-process=image/format,f_auto/resize,m_lfit,limit_1,h_300","明日香2.jpg");
        ThreadTest2 threadTest3 = new ThreadTest2("https://aistyle.art/assets/files/2023-06-30/1688166112-995353-348703237-145251275241612-1956428239713994473-n.jpg","明日香3.jpg");

        threadTest1.start();
        threadTest2.start();
        threadTest3.start();
    }
}
class WebDownloader{
    //
    public void download(String url,String name){
        try{
            FileUtils.copyURLToFile(new URL(url),new File(name));
            System.out.println("下载完成");
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

实现runable接口

public class TestThread3 implements Runnable {
    public static void main(String[] args) {
        TestThread3 testThread3 = new TestThread3();
        new Thread(testThread3).run();

        for (int i = 0; i < 10; i++) {
            System.out.println("我在学习" + i);
        }
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("我在聊天" + i);
        }
    }
}

初识并发问题

package org.example.redisson.JavaThread;

/**
 * @Description:TODO
 * @Author:Administrator
 * @Create 2024/1/12
 */

/**
 * 创建线程方式2:实现runable 接口重写run
 * 执行线程需要啊丢入new Thread(TestThread3)
 * 官方推荐 实现runable接口的方式
 */
public class TestThread4 implements Runnable {

    // 模拟票数
    private int ticketNums = 100;
    @Override
    public void run() {
        while (true){
            // 票剩余0时退出
            if (ticketNums <= 0){
                break;
            }
            // 模拟延时
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // 对票数加锁
            synchronized ((Object)ticketNums){
                // 再次判断
                if (ticketNums <= 0){
                    break;
                }
                System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNums--+"张票");
            }
        }
    }

    public static void main(String[] args) {
        TestThread4 ticket = new TestThread4();

        new Thread(ticket,"陈X华").start();
        new Thread(ticket,"席X辉").start();
        new Thread(ticket,"李X杰").start();
    }
}

龟兔赛跑

public class TestThread5 implements Runnable{
    private static String Winer;
    // 比赛内容
    public void run(){
        // 如果线程是兔子 让他休息20ms
        if(Thread.currentThread().getName().equals("兔子")){
            try{
                Thread.sleep(20);
            }catch(RuntimeException | InterruptedException e){
                e.printStackTrace();
            }
        }
        for(int i = 1;i<= 10;i++){
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
            // 判断比赛是否结束
            Boolean flage = gameOver(i);
            if (flage){
                break;
            }
        }
    }

    public static void main(String[] args){
        TestThread5 testThread5 = new TestThread5();
        new Thread(testThread5,"兔子").start();
        new Thread(testThread5,"乌龟").start();
    }
    public Boolean gameOver(int step){
        // 胜利者诞生 停止比赛
        if(Winer != null){
            return true;
        }
        // 跑过了10 步 停止比赛
        if(step == 10){
            Winer = Thread.currentThread().getName();
            System.out.println("胜利者是"+Winer);
            return true;
        }
        return false;
    }
}

callable

函数式接口 lambda

JDK8 之前的写法


 public class TestLambda2{
// 一个接口只有一个实现方法:叫做函数式接口
interface ILove{
        void love(int a);
    }

public static void main(String[] args){
       ILove i = new I();
       i.love(521);
    }

 class I implements ILove{
        @Override
    public void love(int a){
            System.out.println("i love you " + a);
        }
    }
 } 

简化1:使用静态内部类

# 使用静态内部类

public class TestLambda2{
// 一个接口只有一个实现方法:叫做函数式接口
interface ILove{
        void love(int a);
    }

public static void main(String[] args){
       ILove i = new I();
       i.love(521);

    }
static class I implements ILove{
        @Override
    public void love(int a){
            System.out.println("i love you " + a);
        }
    }
 } 

简化2:局部内部类

public class TestLambda2{
// 一个接口只有一个实现方法:叫做函数式接口
interface ILove{
        void love(int a);
    }

public static void main(String[] args){
    class I implements ILove{
    @Override
    public void love(int a){
            System.out.println("i love you " + a);
        }
    }
       ILove i = new I();
       i.love(521);

    }
 } 

简化3:匿名内部类(通过new 构建 没有方法名)

interface ILove{
        void love(int a);
    }

public class TestLambda2{
// 一个接口只有一个实现方法:叫做函数式接口

public static void main(String[] args){
    ILove  i = new ILove(){
        @Override
        public void love(int a){
            System.out.print("i love you " + a)
        }
    };
        i.love(521);
    }
 } 

最终lambda版本

interface ILove {
    void love(int a,int b);
}
public class TestLambda2 {
    // 一个接口只有一个实现方法:叫做函数式接口
    public static void main(String[] args) {
        ILove i = (a,b) -> {
                System.out.println("i love you " + a+b);
        };
        i.love(520,521);
    }
}
Lambda总结

1、接口中只能有一个方法;
2、lambda执行业务逻辑时 必须带{},除非业务逻辑只有一行
3、多个参数 也可以去掉参数类型(全部去掉)

线程状态:

创建 new Thread()

就绪(等待cpu调度) start();

阻塞(阻塞结束后 等待cpu调度) sleep()、wait()或同步锁

sleep
sleep(ms) 指定当前线程阻塞的毫秒数;
sleep 存在异常InterruptedException;
sleep 时间到达后线程进入就绪状态;
sleep 可以模拟网络延时。倒计时等
每一个对象都有一把锁。sleep不会释放锁;
/**
 * @Description: 联系sleep 倒计时
 * @Author:Administrator
 * @Create 2024/1/13
 */

public class TestThreadSleep{
    public static void main(String[] args) throws InterruptedException {
        tenShutDown();
    }

    static void tenShutDown() throws InterruptedException {
        int num = 10;
        while (true){
            Thread.sleep(1000);
            System.out.println( num-- );
            if (num <= 0){
                break;
            }
        }

    }
}

join 使线程阻塞,相等于vip先执行
/**
 * @Description:测试 join,会使线程阻塞
 * @Author:Administrator
 * @Create 2024/1/13
 */

public class TestThreadJoin implements Runnable{

    @Override
    public void run() {
        for (int i = 1; i < 101; i++) {
            System.out.println("vip来了 统统闪开~ !"+i);
        }
    }
    public static void main(String[] args) throws InterruptedException {
        TestThreadJoin testThreadJoin = new TestThreadJoin();
        Thread thread = new Thread(testThreadJoin);
        thread.start();
        
        for (int i = 1; i < 101; i++) {
            System.out.println("main"+ i);
            if(i == 10){
                thread.join();// 强制执行 run方法 线程
            }
        }
    }
}

运行

start()、run()

销毁

不建议用stop、die废弃或官方不推荐的方法
  • 推荐基数的方式 停止线程
/*
 * @Description:不建议用stop、die废弃或官方不推荐的方法
 * 推荐基数的方式 停止线程
 * @Author:Administrator
 * @Create 2024/1/13
 */
public class TestThreadStop implements Runnable {
    public Boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println("走了" + i++ + "步数");
        }
    }

    // 设置一个公开的停止方法
    public void stop() {
        this.flag = false;
    }

    public static void main(String[] args) {
        TestThreadStop testThreadStop = new TestThreadStop();

        new Thread(testThreadStop).start();

        for (int i = 0; i < 100; i++) {
            System.out.println("main"+ i);
            if (i == 90) {
                // 循环90次的时候 停止线程
                testThreadStop.stop();
                System.out.println("线程该停止了");
            }
        }
    }

}

观察线程的状态

启动前:new
启动后:runnable
运行:Timed-waiting
结束: TERMINATED

线程的优先级

优先级:1-10;数字越大优先级越高;

守护线程

1、通过Thread.seDeamon(true) 设置
2、在线程start 前设置
3、用户线程挂掉,守护线程也会等待cpu调度挂掉

线程同步机制

多个线程同时对公共对象操作,就是并发问题
如何解决并发安全问题
1、使用线程同步队
sync 同步锁:
一个线程持有锁 会导致其他所有需要次锁的线程挂起
一定会损失性能
优先级高的线程,等待优先级低的线程 释放锁会有性能问题 鱼和熊掌不可兼得

三大不安全案例

1、两人同时对同一张银行卡取钱(超取问题)
2、网上买票(超卖问题)
3、1000个线程对ArrayList同时操作,数据不一致(array.add方法是根据下标位置,多个线程可能会同时锁定下标位置)

同步方法及同步块

sync

CopyOnWriteArrayList

JUC Java并发编程
java util.concurren.copyOnWirteArrayList;线程安全的数据类型

死锁

a 想占用 b的资源
b 想占用 a的资源 
都在等对方释放

Lock锁

ReentrantLock实现了Lock 是可重入锁
copyOnWirteArrayList 中使用了;
Sync和Lock的区别
Lock是显式锁 需要手动开启、关闭,sync是隐式锁 出了区域自动释放
Lock只有代码块锁,sync有代码块锁也有方法锁
使用Lock锁,JVM将花费较少的时间来调度线程,性能更好

生产者消费问题(线程协作)

生产者消费者问题
假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取出消费
如果仓库中没有产品,则生产者将产品放入仓库,否则停止并等待并等待仓库中的产品被消费者取走为止
如果仓库中放有产品,则消费者可以将产品取走消费,否则停止生产并等待,直到仓库中再次放入产品为止

管程法

信号灯法

设置flag信号灯管理 生产消费的通信 flag为true消费,否则生产

线程池

Executor

总结

posted @   Only_Aptx-4869  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示