Java学习笔记(23)

多线程

并发

并行

多线程实现方式

1.继承Thread类

自己创建一个类extends thread类

Start方法开启线程,自动执行重写之后的run方法

2.实现runable接口

自己创建一个类implements runnable

Myrun不能直接使用getname方法,因为这个方法是thread类的方法

所以需要得到当前线程的thread对象,再用getname方法

3.用callable接口和future接口方法

抽象方法run没有返回值,获取不了运行结果

实现callable接口

重写call方法

Future接口不能直接用,要用他的实现类futuretask管理线程运行结果

Thread的方法

Getname

没有起名,有默认名字:Thread-0,Thread-1.。。

Setname

设置线程名字,可以用set,也可以用构造方法,但是构造方法不能继承,要自己重新写个构造方法,通过super继承父类的构造方法

CurrentThread

Sleep 静态方法 用Thread.sleep调用

抢占式调度

随机

优先级最高10,最小1,默认5

Setpriority(int)

Getpriority

守护线程

SetDaemon(true)

非守护和守护默认没有优先级之分

非守护结束,守护慢慢就也会结束

出让线程

Thread.yield()

让结果每一个线程尽可能均匀运行

插入线程

线程的生命周期

有执行资格:有资格去抢CPU的执行权

没有执行权:还没抢到执行权,不能执行代码

线程安全

Ticket要用static修饰,这样所有这个类的对象就可以共享ticket

为什么会出现这个问题?

执行代码时,线程随时都会被其他线程抢夺执行权

如何解决?

同步代码块

让一个线程执行完完整的一次同步代码块里的代码,才可以重新抢夺执行权

Synchronized(锁对象){}

锁对象:是任意的,但是一定是唯一的,前面用static修饰

锁对象可以是本类的字节码文件

同步方法

如果想把一个方法里面所有的代码都锁起来,就不需要同步代码块

直接将synchronized加在方法上

用runable的时候,由于只需要创建一次,所以里面的ticket就可以不用static修饰

Stringbuffer用于多线程环境,里面的方法和stringbuilder一样的

Lock锁

是一个接口,创建对象要用实现类reentrantlock

以上代码可能出现的问题:

  1. 如果lock没有用static修饰

则会所有的线程都会创建一个lock,重复ticket,超出范围的问题又会出现,所以要加static修饰,即所有线程共享一个lock,就能解决

2.程序不停止?

没有执行lock.unlock()方法,有线程一直停留在lock.lock()方法,所以程序没有停止

如何避免?

把unlock写到finally中,保证unlock一定会执行

死锁

不要让两个锁嵌套起来写,这样程序就运行不下去

生产者和消费者

等待唤醒机制

生产者:生产数据

消费者:消费数据

消费者等待

生产者等待

完整机制

方法

Wait

一般用notifyall

这几个方法要通过锁对象来进行调用

重写run方法的套路

Desk

Foodie

Cookie

测试类

第二种实现方式:阻塞队列方式

  1. 数组,有界
  2. 链表,无界

生产者和消费者要使用同一个阻塞队列

不需要在写锁对象,因为put和take方法的底层就已经有锁了

Take有返回值,类型和put进去的数据一样

线程的状态

Java没有定义运行状态,只有剩下的六种状态

为什么没有?

因为线程抢到CPU的执行权之后,当前线程就会交给操作系统管理,虚拟机就不会再管这个线程了

java 复制代码
package exericise;

public class exercise1 {
    public static void main(String[] args) {

        window t1 = new window();
        window t2 = new window();
        t1.setName("窗口1");
        t2.setName("窗口2");
        t1.start();
        t2.start();
    }
}

package exericise;

public class window extends Thread{
    static int ticket  =1000;
    @Override
    public void run() {
        while (true) {
            synchronized (exercise1.class){
                if (ticket != 0){
                    ticket--;
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println(getName() + "还有"+ticket+"张票");
                }else {
                    break;
                }
            }
        }
    }
}
java 复制代码
package exericise;

public class exercise2 {
    public static void main(String[] args) {

        Person t1 = new Person();
        Person t2 = new Person();
        t1.setName("Person1");
        t2.setName("Person2");
        t1.start();
        t2.start();
    }
}

package exericise;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Person extends Thread {
    static int gift = 1000;
    static Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true) {
            lock.lock();
            try {
                if (!(gift < 10)) {
                    System.out.println(getName() + "送出第" + gift + "个礼物");
                    gift--;
                } else {
                    break;
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
    }
}
java 复制代码
package exericise;

public class exercise3 {
    public static void main(String[] args) {
        Number t1 = new Number();
        Number t2 = new Number();
        t1.setName("线程1");
        t2.setName("线程2");
        t1.start();
        t2.start();
    }
}

package exericise;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Number extends Thread{
    static int start = 1;
    static int end = 100;
    static Lock lock = new ReentrantLock();
    @Override
    public void run() {

        while (true) {
            lock.lock();
            try {
                if (start <= end) {
                    //判断是不是奇数
                    if (start %2 == 1) {
                        //是就打印
                        System.out.println(getName() + ":" + start);
                    }
                    start++;
                }else {
                    //超过范围
                    break;
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
    }
}
java 复制代码
package exericise;

import java.util.Arrays;
import java.util.Random;

public class exercise4 {
    public static void main(String[] args) {
        //随机分成3个红包
        Random r = new Random();
        for (int i = 0; i < redBao.arr.length; i++) {
            if (i == redBao.arr.length - 1) {
                redBao.arr[i] = redBao.redPocket;
            }else {
                redBao.arr[i] = r.nextDouble(0.01,redBao.redPocket);
                redBao.redPocket -= redBao.arr[i];
            }
        }
        System.out.println(Arrays.toString(redBao.arr));

        redBao rb1 = new redBao();
        redBao rb2 = new redBao();
        redBao rb3 = new redBao();
        redBao rb4 = new redBao();
        redBao rb5 = new redBao();

        rb1.setName("No.1");
        rb2.setName("No.2");
        rb3.setName("No.3");
        rb4.setName("No.4");
        rb5.setName("No.5");

        rb1.start();
        rb2.start();
        rb3.start();
        rb4.start();
        rb5.start();

    }
}
package exericise;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class redBao extends Thread{
    static double redPocket = 100;

    //标记是否已经抢到过
    boolean flag = false;
    static double[] arr = new double[3];

    static Lock lock = new ReentrantLock();
    static int index = 0;
    static int end = 1;
    @Override
    public void run() {


            lock.lock();
            try {

                if (!flag && index <= 2){
                    //还没抢到过红包
                    System.out.println(getName() + "抢到了" + arr[index] + "块钱");
                    index++;
                    flag = true;
                }
                if (end >3) {
                    System.out.println(getName() + "没抢到");
                }
                end++;

            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }


    }
}

在run方法中定义一个集合,则所有的进程都会在自己的栈中的run方法里创建出自己的集合,这个集合在不同的进程中独立,互不影响

注意:其实每一个线程都会有自己独立的栈,包括main,里面创建的元素互不影响(除非是static)

线程池

创建线程浪费时间

用完直接丢弃,浪费资源

原理

一般不会关闭线程池:因为服务器24小时都会运行,所以随时都会新任务进来,所以一般不会关闭线程池

Submit:提交任务

Shutdown:销毁线程池

0

自定义线程池

什么时候创建临时线程?

核心线程已被占用,而且排队队伍已满,这是才创建临时线程

先提交的任务,不一定先执行

如图,任务4 5 6在排队,临时线程处理任务7 8

当提交的任务数量大于核心线程数+临时线程数+队伍长度,剩下的任务10就会触发任务拒绝策略

自定义线程池,设置七个参数

ThreadPoolExecutor

到底怎么设置才合适?

最大并行数

系统处理器的线程数,4核8线程,8就是最大并行数

CPU密集型运算:读取文件较少,计算数据较多

为什么+1:如果前面的线程出问题,则多出来的线程就可以顶上,不浪费cpu的时钟周期不被浪费

IO密集性运算:现在的项目大多都是IO密集性的,读取服务器文件操作多

怎么得到计算时间?

通过thread dump的工具来测试计算时间

相关推荐
困死,根本不会13 小时前
Git 远程连接仓库学习笔记(本地→GitHub)
笔记·git·学习
青稞社区.13 小时前
ROLL 团队分享:面向多轮交互 Agentic 场景的 Rollback 课程学习机制探索与实践
人工智能·经验分享·学习·交互
深耕半夜13 小时前
linux内存学习记录
linux·服务器·学习
马猴烧酒.13 小时前
【JAVA算法|hot100】贪心算法类型题目详解笔记
java·开发语言·ide·笔记·算法·spring·贪心算法
ADHD多动联盟14 小时前
如何通过行为矫正方案改善孩子的情绪问题和学习能力?
学习·学习方法·玩游戏
未来可期叶14 小时前
【软考网工】第一章 计算机网络概论:高频考点(OSI/TCP/IP+数据封装)
网络·笔记·网络协议·tcp/ip·计算机网络·软考·备考
Shining059614 小时前
前沿模型系列(二)《科学多模态大模型》
人工智能·学习·其他·性能优化·infinitensor
TrueDei14 小时前
10年学习Linux大师说这些命令不会等于不会Linux
linux·运维·学习
im_AMBER14 小时前
前端性能优化之首屏提速
前端·学习·性能优化
AnalogElectronic14 小时前
树莓派 RP2040 学习笔记1
笔记·学习