首页 > 编程语言 >Java线程

Java线程

时间:2024-08-25 16:18:11浏览次数:13  
标签:Java Thread void public 线程 new class

一、线程的介绍

1.1.程序

为完成特定任务,用某种语言编写的一组指令的集合。(代码)

1.2.进程

  • 进程就是指运行中的程序,启动一个进程,操作系统就会为该进程分配内存空间。
  • 进程是程序的一次执行过程,或是正在运行的一个程序,是动态过程:有它自己的产生、存在和消亡的过程

1.3.线程

  • 线程是由进程创建的,是进程的一个实体
  • 一个进程可以拥有多个线程
1.31.单线程

同一个时刻,只能执行一个线程

1.32.多线程

同一个时刻,可以进行多个线程。(比如一个QQ进程,可以同时打开多个连天窗口)

1.33.并发

同一时刻,多个任务交替进行。简单来说,单核CPU实现的多任务就是并发。

1.34.并行

同一时刻,多个任务同时执行。多核CPU可以实现并行。

注:并发和并行可同时进行

二、线程的基本使用

2.1.创建线程的两种方式

2.11继承 Thread 类,

重写run 方法;

2.22实现Runnable接口,

重写run 方法。

Java中,类是单继承,在某些情况下,一个类可能已经继承了某个父类,这个时候就可以通过实现Runnable接口来创建线程。

image-20240823165812004

例1:继承Thread类,创建线程

要求:1.编写一个线程,该线程每隔2秒,在控制台输出"你好!"

​ 2.改进上述线程,当输出10次"你好!",线程关闭

//3.使用JConsole监控线程执行情况

package thread.thread02;

/**
 * @author yeye
 * @desc  通过继承Thread类创建线程
 * 1.编写一个线程,该线程每隔2秒,在控制台输出"你好!"
 * 2.改进上述线程,当输出10次"你好!",线程关闭
 * @date 2024/8/24 10:52
 */
public class Thread01 {
    public static void main(String[] args) throws InterruptedException {

        //创建一个Cat对象,可以看做是一个线程
        Cat cat = new Cat();
        //启动线程,最终会执行cat的run()方法
        cat.start();
        //当main线程启动一个子线程Thread-0,主线程不会阻塞,会继续执行

        System.out.println("主线程继续执行"+"线程名:"+Thread.currentThread().getName());
        for (int i = 0; i < 10; i++) {
            System.out.println("主线程执行"+i+"次");
            //让主线程休眠1秒
            Thread.sleep(1000);
        }
    }
}

/**
 * 如果一个类继承了Thread类,那么这个类就成为一个线程类。
 * 线程类要重写run()方法,该方法是线程的入口方法。
 * Thread类中的run()方法 实际上实现类Runnable接口的run()方法。
 */
class Cat extends Thread{

    int times = 0;
    @Override
    public void run() { //重写run()方法,写上线程要执行的代码
        while (true){
            //该线程每隔2秒,在控制台输出"你好!"
            System.out.println("你好!"+(++times)+"线程名:"+Thread.currentThread().getName());
            //让线程休眠2秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //当输出10次"你好!",线程关闭
            if(times == 100){
                break;
            }
        }
    }
}

例2:实现Runnable接口,创建线程

要求:编写一个程序,每隔1秒,在控制台输出"你好",当输出10次后,自动退出,使用实现Runnable接口的方法实现。这里底层使用了设计模式,是静态代理。

package thread.thread02;

/**
 * @author yeye
 * @desc 通过实现 Runnable 接口创建线程
 * @date 2024/8/24 12:09
 */
public class Thread02 {
    public static void main(String[] args) {
        Person person = new Person();
        //person.start();不能调用start方法
        //创建Thread对象,把person对象(实现Runnable接口),放入Thread
        Thread thread = new Thread(person);
        thread.start();

    }
}
class Person implements Runnable { // 实现 Runnable 接口,创建线程
    int count = 0;
    @Override
    public void run() { // 重写 run() 方法-普通方法,没有正真实现多线程
        while(true){
            System.out.println("你好"+(++count)+Thread.currentThread().getName());

            //休眠1秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(count ==10){
                break;
            }
        }

    }
}

例3:多线程执行

要求:编写一个程序,创建两个线程,一个线程每隔1秒输出"今天很热!",输出10次退出,另一个线程每隔1秒输出"今天不冷",输入5次退出。

package thread;

/**
 * @author yeye
 * @desc main线程启动两个线程
 * 创建两个线程,一个线程每隔1秒输出"今天很热!",输出10次退出,
 * 另一个线程每隔1秒输出"今天不冷",输入5次退出。
 * @date 2024/8/24 14:54
 */
public class Thread03 {
    public static void main(String[] args) {
        A1 a1 = new A1();
        A2 a2 = new A2();
        Thread thread = new Thread(a1);
        Thread thread2 = new Thread(a2);
        thread.start();
        thread2.start();
    }
}
class A1 implements Runnable{
    int count = 0;
    @Override
    public void run() {
        //每隔1秒输出"今天很热!",输出10次退出
        while (true){
            System.out.println("今天天气很热! "+(++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 10) {
                break;
            }
        }
    }
}
class A2 implements Runnable{
    int count = 0;
    @Override
    public void run() {
        //每隔1秒输出"今天不冷",输入5次退出。
        while(true) {
            System.out.println("今天天气不冷!"+(++count));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 5) {
                break;
            }
        }
    }
}
2.23继承Thread和实现Runnable的区别
  1. 从Java的设计来看,通过继承Thread或者实现Runnable接口来创建线程本质上来说没有区别——都是通过stare()方法调用stare0()方法实现多线程;

  2. 实现Runnable接口方式更适合多线程共享资源的情况,并且避免了单继承的限制

例:实现三个窗口同时买票,票数一共100张。

1.通过继承Thread的方式

package thread.ticket;

/**
 * @author yeye
 * @desc
 * @date 2024/8/24 16:03
 */
public class SellTicket01 {
    public static void main(String[] args) {
        TicketWindow tw1 = new TicketWindow();
        TicketWindow tw2 = new TicketWindow();
        TicketWindow tw3 = new TicketWindow();
        tw1.start();
        tw2.start();
        tw3.start();
    }
}
//继承Thread类的方式,实现三个窗口同时买票
class TicketWindow extends Thread {
    public static int ticketNum =100; //让多个线程共享ticketNum
    @Override
    public void run() {
        while(true) {
            if (ticketNum > 0) {
                System.out.println("窗口" + Thread.currentThread().getName() + "售出1张票,还剩" + (--ticketNum)+"张票");
                //休眠50毫秒
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else{
                System.out.println("窗口"+Thread.currentThread().getName()+"票已售空,明天再来!");
                break;
            }
        }
    }
}

2.通过实现Runnable接口的方式

package thread.ticket;

/**
 * @author yeye
 * @desc
 * @date 2024/8/24 16:03
 */
public class SellTicket02 {
    public static void main(String[] args) {
        TicketWindow02 window1 = new TicketWindow02();
        new Thread(window1).start();
        new Thread(window1).start();
        new Thread(window1).start();
    }
}
//继承Thread类的方式,实现三个窗口同时买票
class TicketWindow02 extends Thread {
    public int ticketNum =100; //让多个线程共享ticketNum
    @Override
    public void run() {
        while(true) {
            if (ticketNum > 0) {
                System.out.println("窗口" + Thread.currentThread().getName() + "售出1张票,还剩" + (--ticketNum)+"张票");
                //休眠50毫秒
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else{
                System.out.println("窗口"+Thread.currentThread().getName()+"票已售空,明天再来!");
                break;
            }
        }
    }
}

2.2.线程终止

  1. 当线程完成任务后,会自动终止;
  2. 使用变量来控制run()方法退出的方式停止线程,即通知方式

例1:启动一个线程t,要求在main线程中停止线程t

package thread.exit_thread;

/**
 * @author yeye
 * @desc 启动一个线程t,要求在main线程中停止线程t
 * @date 2024/8/24 16:54
 */
public class ThreadExit01 {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.start();
        
        //主线程休眠10秒后,在通知t线程退出
        Thread.sleep(10000);
        /**
         * 如果希望main线程控制t线程终止,必须可以修改loop
         * 让t退出run()方法,从而终止t线程
         */
        t.setLoop(false);
    }
}
class T extends Thread {
    private int count = 0;
    //设置一个控制变量
    public Boolean loop = true;
    @Override
    public void run() {
        while (loop) {
            System.out.println("线程t运行" + (++count));

            //休眠1秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public void setLoop(Boolean loop) {
        this.loop = loop;
    }
}

2.3线程常用的方法

2.31常用方法1:

1.setName () //设置线程的名称

2.getName() //返回该线程的名称

3.start() //启动线程;Java虚拟机底层调用该线程的start0()方法

4.run() //调用线程对象的run 方法

5.setPriority() //更改线程的优先级

6.getPriority() //获取线程的优先级

7.sleep() //在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)

8.interrupt() //中断线程,并没有正真中断线程,而是中断正在休眠的线程

注意:

  1. start底层会创建新的线程,调用run,run就是一个简单的方法调用,不会启动新线程

  2. 线程优先级的范围

    MAX_PRIORITY - 10
    MIN_PRIORITY - 1
    NORM_PRIORITY - 5
    
  3. interrupt,中断正在休眠的线程

  4. sleep:线程的静态方法,使当前方法休眠

例1:上述1-8方法的演示

package thread.method;

/**
 * @author yeye
 * @desc
 * @date 2024/8/24 17:51
 */
public class ThreadMethod01 {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.setName("椰椰");
        t.setPriority(Thread.MAX_PRIORITY);
        t.start(); //启动子线程

        //主线程打印5个"beautiful",然后中断子线程的休眠
        for(int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.println("beautiful");
        }
        System.out.println(t.getName()+"线程的优先级"+t.getPriority());
        t.interrupt(); //中断子线程的休眠
    }
}
class T extends Thread{
    @Override
    public void run() {
        while(true){
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "背单词" + i);
            }
            try {
                System.out.println(Thread.currentThread().getName() + "休眠10秒");
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + "被中断了");
            }
        }
    }

}
3.32常用方法2:

1.yield: 线程的礼让。让出CPU,让其他线程执行,但礼让的线程时间不确定,所以也不一定礼让成功

2.join:线程的插队。插队的线程一旦插队成功,则肯定先执行完插队的线程所有的任务

例: join()方法和yield方法的演示,主线程吃10个包子,子线程吃10个包子,主线程让子线程先吃。

package thread.method;

/**
 * @author yeye
 * @desc
 * @date 2024/8/24 22:25
 */
public class ThreadMethod02 {
    public static void main(String[] args) throws InterruptedException {
        Test t = new Test();
        t.start(); //启动线程

        for(int i=1; i<=10; i++) {
            Thread.sleep(1000);
            System.out.println("主线程吃了"+i+"个包子");
            if(i == 5) {
                System.out.println("主线程让子线程先吃");
                //线程礼让,让子线程先执行,不一定成功
                //Thread.yield(); //让出CPU,让子线程先执行
                //join,线程插队,让子线程先执行完毕,再执行主线程
                t.join(); //让子线程执行完毕,等待子线程结束
                System.out.println("子线程结束, 继续执行主线程");
            }
        }

    }
}
class Test extends Thread {

    @Override
    public void run() {
        for(int i=1; i<=10; i++) {
            try {
                Thread.sleep(1000); //休眠1秒钟
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程吃了"+i+"个包子");
        }
    }
}

实例:线程插队练习

要求:1.主线程每隔1s,输出 我要减肥,一共十次;

​ 2.到输出到第五次时,启动子线程(要求实现Runnable接口),每隔1秒输出 减肥好累,等子线程输出10次退出;

​ 3.主线程继续输出 我要减肥,直到主线程退出。

package thread.method;

/**
 * @author yeye
 * @desc
 * @date 2024/8/24 23:31
 */
public class ThreadMethodTest01 {
    public static void main(String[] args) throws InterruptedException {
        TT tt = new TT();
        Thread thread = new Thread((tt));

        for(int i = 1;i <=10;i++){
            System.out.println("我要减肥"+i);
            if(i == 5) {
                System.out.println("不想减肥了,好累");
                thread.start(); //启动子线程
                thread.join(); //礼让子线程结束,继续执行主线程
                System.out.println("子线程结束,继续执行主线程");
            }
            Thread.sleep(1000);
        }
    }
}
class TT implements Runnable {

    @Override
    public void run() {
        while (true) {
            for(int i =1;i<=10;i++){
                System.out.println("减肥好累" + i);
                //休眠1秒
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            break;
        }
    }
}
2.32常用方法3:

1.用户线程:也叫工作线程,当线程的任务执行完或以通知方法结束

2.守护线程:一般为工作线程服务,当所有用户线程结束,守护线程自动结束

常见的守护线程:垃圾回收机制

例:

package thread.method;

/**
 * @author yeye
 * @desc
 * @date 2024/8/25 0:26
 */
public class ThreadMethod03 {
    public static void main(String[] args) throws InterruptedException {
        MyDaemonThread myDaemonThread = new MyDaemonThread();
        //如果我们希望当主线程结束后,子线程可以自动结束,只需将子线程设置为守护线程即可
        myDaemonThread.setDaemon(true);
        myDaemonThread.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("重新开始减肥");
            Thread.sleep(1000);
        }
    }
}
class MyDaemonThread extends Thread {
    @Override
    public void run() {
        for(;;){
            System.out.println("减肥失败");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2.4.线程的生命周期

线程状态:

  • NEW:尚未启动的线程处于此状态;
  • RUNNABLE:在JAVA虚拟机中执行的线程处于此状态,由于调度机的调度处理,可分为READY和RUNNING;
  • WAITING:正在等待另一个线程执行特定动作的线程处于此状态;
  • TIMED_WAITING:正在等待另一个线程执行动作达到指定等待时间的状态处于次状态
  • BLOCKED:被阻塞等待监视器锁定的线程处于此状态;
  • TERMINATED:已退出的线程处于次状态。

image-20240825110019385

演示:

package thread.threadstate;

/**
 * @author yeye
 * @desc
 * @date 2024/8/25 10:49
 */
public class ThreadState01 {
    public static void main(String[] args) throws InterruptedException {

        T t = new T();
        System.out.println(t.getName()+"状态是:"+t.getState());
        t.start();

        while(Thread.State.TERMINATED != t.getState()){
            System.out.println(t.getName()+"状态是:"+t.getState());

            Thread.sleep(1000);
        }
        System.out.println(t.getName()+"状态是:"+t.getState());
    }
}
class T extends Thread {
    @Override
    public void run() {
        while(true){
            for(int i=0;i<10;i++){
                System.out.println(i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            break;
        }
    }
}

2.5线程同步

2.51.线程同步机制
  1. 同步:在多线程编程,一些敏感的数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多只有一个线程访问,以保证数据的完整性。

  2. 也可以理解为:线程同步,即有一个线程对内存进行操作时,其他线程都不可以对这个内存地址经行操作,直到该线程完成操作,其他线程才能对该线程进行操作。

2.52.同步具体方法 ——synchronized
  1. 同步代码块

    synchronized (对象){ //得到对象的锁,才能操作同步代码块
        //需要同步的代码块
    }
    
  2. synchronized还可以放在方法的声明中,以表示整个方法为同步方法

//例如
public synchronized void t(String name){ //同步方法
    //需要同步的代码块
}

例:用第二种方法完善三个售票窗口卖票问题

package thread.synchronized_;

/**
 * @author yeye
 * @desc
 * @date 2024/8/25 13:15
 */
public class SellTicket03 {
    public static void main(String[] args) {

        TicketSeller03 ticketSeller = new TicketSeller03();
        new Thread(ticketSeller).start();//第一个窗口
        new Thread(ticketSeller).start();//第二个窗口
        new Thread(ticketSeller).start();//
    }
}
//实现Runnable接口,使用synchronized实现线程同步
class TicketSeller03 implements Runnable {
    private int ticketNumber = 100;
    public Boolean loop = true; //控制run方法变量

    public synchronized void sell(){ //同步方法,在同一时刻,只能有一个线程来执行sell方法
        if (ticketNumber <= 0) {
            System.out.println("票已售完");
            loop = false;
            return;
        }
        System.out.println("窗口"+Thread.currentThread().getName()+"售出1张票,还剩" + ticketNumber-- + "张票");
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() { //同步方法,在同一时刻,只能有一个线程来执行run方法
        while(loop) {
            sell();

        }
    }
}

2.6互斥锁

2.61.基本介绍
  1. Java中,引用对象互斥锁的概念,用来保证共享数据操作的完整性;
  2. 每个对象都对应一个可称为"互斥锁"的标记,这个标记用来保证在任一时刻,只有一个线程访问该对象;
  3. 关键字synchronized与对象的互斥锁联系。当某个对象用synchronized修饰时,表明这个对象在任一时刻只能被一个线程访问;
  4. 同步的局限性:导致程序的执行效率降低;
  5. 同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象);
  6. 同步方法(静态的)的锁为当前类本身。类.class
2.62注意事项
  1. 如果同步方法没有使用static修饰,默认锁对象是this;
  2. 如果同步方法使用static修饰,默认锁对象是:当前类.class
  3. 实现互斥锁的步骤:
    • 需要先分析上锁的代码;
    • 选择同步方法或同步代码块;
    • 要求多个线程的锁为同一个。

例:使用互斥锁解决售票问题

2.52例题——同步方法、下述例题——同步代码块

package thread.synchronized_;

/**
 * @author yeye
 * @desc
 * @date 2024/8/25 13:15
 */
public class SellTicket02 {
    public static void main(String[] args) {

        TicketSeller02 ticketSeller = new TicketSeller02();
        new Thread(ticketSeller).start();//第一个窗口
        new Thread(ticketSeller).start();//第二个窗口
        new Thread(ticketSeller).start();//
    }
}
//实现Runnable接口,使用synchronized实现线程同步
class TicketSeller02 implements Runnable {
    private int ticketNumber = 100;
    public Boolean loop = true; //控制run方法变量
    Object object = new Object();//互斥锁对象
    
    //    //同步方法(静态方法)的锁是对象本身,锁是TicketSeller02.class
//    public synchronized static void maipiao() {}
//    //静态方法中,实现同步代码块,锁是TicketSeller02.class
//    public static void maipiao2() {
//        synchronized (TicketSeller02.class) {
//            System.out.println("hello");
//    }

    public  void sell(){
        synchronized (/**this*/object) { //同步代码块,互斥锁还是this对象,也可以是其他对象,如object
            if (ticketNumber <= 0) {
                System.out.println("票已售完");
                loop = false;
                return;
            }
            System.out.println("窗口" + Thread.currentThread().getName() + "售出1张票,还剩" + ticketNumber-- + "张票");
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void run() { //同步方法,在同一时刻,只能有一个线程来执行run方法
        while(loop) {
            sell();

        }
    }
}

2.7线程的死锁

2.71基本介绍

多个线程都占用对方的资源锁,但不肯想让,导致线程死锁。

2.72应用案例

小明:你先让我玩手机,我才完成作业

妈妈:你先完成作业,才让你玩手机

例:

package thread.deadlock;

/**
 * @author yeye
 * @desc
 * @date 2024/8/25 15:10
 */
public class ThreadDeadLock01 {
    public static void main(String[] args) {
        //模拟死锁现象
        DeadLockDemo A = new DeadLockDemo(true);
        A.setName("现象A");
        DeadLockDemo B = new DeadLockDemo(false);
        B.setName("线程B");
        A.start();
        B.start();

    }
}
class DeadLockDemo extends Thread {
    public Object ob1 = new Object(); //保证多线程,共享同一个对象,这里使用static修饰
    public Object ob2 = new Object();
    Boolean flag;

    public DeadLockDemo(Boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        //如果flag为true,线程A就会先得到ob1的对象锁,然后尝试获取ob2的对象锁
        //如果线程A得不到ob2的锁,就会发生Blocked
        //如果flag为false,线程B就会先得到ob2的对象锁,然后尝试获取ob1的对象锁
        if (flag) {
            synchronized (ob1) { //对象互斥锁,下面就是同步代码块
                System.out.println(Thread.currentThread().getName() +  "进入1");
                synchronized (ob2) {
                    System.out.println(Thread.currentThread().getName() +  "进入2");
                }
            }
        }else {
            synchronized (ob2) {
                System.out.println(Thread.currentThread().getName() +  "进入3");
                synchronized (ob1) {
                    System.out.println(Thread.currentThread().getName() +  "进入4");
                }
            }
        }
    }
}

2.8释放锁

2.81释放锁的情况
  1. 当线程的同步方法、同步代码块执行结束

    如:上厕所,上完厕所,打开门出来

  2. 当前线程在同步方法、同步代码块中遇到break、return

    如:上厕所,突然地震,跑出来

  3. 当前线程在同步方法、同步代码块中出现了未处理的Exception或Error,导致异常结束

    如:上厕所,没带纸,出来拿纸

  4. 当前线程在同步方法、同步代码块中执行了对象的wait()方法,当前线程暂停。并释放锁

    如:上厕所,感觉不强烈,出来酝酿,等会再进去

2.82不会释放锁的情况
  1. 当前线程执行同步方法、同步代码块,调用Thread.sleep()、Thread.yield()方法,只会暂停当前线程,不会释放锁

    如:玩手机,玩累了,休息一下眼睛,然后继续玩

  2. 当前线程执行同步方法、同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁

标签:Java,Thread,void,public,线程,new,class
From: https://www.cnblogs.com/wmshun/p/18379056

相关文章

  • [Javascript] How to do big integers sum
    /***Bigintegersum*Usingstringstorepresentbigintegers*@param{string}a*@param{string}b*@returns{string}*/functionbigIntSum(a,b){constmaxLength=Math.max(a.length,b.length);constaStr=a.padStart(maxLength,"0&......
  • [Javascript] Refactor blocking style code to stream style for fetching the strea
    WhenyouuseChatGPT,theresponsecomesinstream,sothatitcanappearsonscreenwheneverdatacomebackfromserver,wedon'tneedtowaitalldatacompletedthenshowingthedatatousers. Hereiscodewhichneedtobeimproved,becausethis......
  • ZBlog搭建的网站有的时候会提示【JavaScript加载失败】
    经常会有朋友反映,自己通过ZBlog搭建的网站偶尔会出现【JavaScript加载失败】这样的提示。那么,当遭遇此种状况时究竟应当如何应对呢?首先,您需要仔细检查自己所使用的浏览器版本是否太过陈旧(例如像IE6/7/8之类的旧版本),或者是否因为所使用的插件出现错误从而损坏了系统的JS文......
  • ## 已解决:`java.lang.ClassCastException: class java.lang.Integer cannot be cast t
    在Java开发中,类型转换错误是常见的异常之一。java.lang.ClassCastException:classjava.lang.Integercannotbecasttoclassjava.lang.Long表示在尝试将一个Integer类型的对象强制转换为Long类型时出现了错误。这种错误可能会导致程序运行时崩溃,因此需要正确地......
  • Java毕业设计作品(113):基于thymeleaf前后端分离 棋牌室会员预约管理系统设计与实现
      博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。项目配有对应开发文档、开题报告、任务书......
  • DsExcel / GcExcel 7.2.0 for Java
    Excel文档解决方案(DsExcel) .NET和Java版本在v7.2版本中继续提供令人兴奋的新功能和增强功能。此更新引入了对许多高级MicrosoftExcel功能的支持,为用户提供了更强大、更灵活的工具。DsExcel模板的重大改进增强了模板创建的功能集和性能。此外,此版本还提供了与Spread......
  • 字符串值提取工具-10-java 执行表达式引擎
    值提取系列字符串值提取工具-01-概览字符串值提取工具-02-java调用js字符串值提取工具-03-java调用groovy字符串值提取工具-04-java调用java?Janino编译工具字符串值提取工具-05-java调用shell字符串值提取工具-06-java调用python字符串值提取工具-07-ja......
  • Java Comparable接口-自然排序
    什么是Comparable排序接口?Comparable接口是Java提供的一个用于对象排序的机制,它允许类的实例自然排序,即定义对象的默认排序顺序。Comparable接口概述Comparable接口是属于Java.lang包。它主要作用是提供一个统一的比较方法,用于对类的对象进行排序。作用:自然排序:是......
  • Java计算机毕业设计实体店管理系统(开题+源码+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着消费市场的日益繁荣与消费者需求的多元化,实体店作为传统零售业态,正面临着前所未有的挑战与机遇。在电商冲击下,实体店需通过数字化转型来提升顾客......
  • java计算机毕业设计校园零食售卖系统小程序(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着数字化时代的到来,校园生活日益便捷化、智能化。在校园环境中,学生对于零食的需求量大且多样化,传统的线下零食售卖方式已难以满足学生随时随地、个......