JUC并发编程之Java线程(二)

2023-11-07

二、Java线程

2.1 创建和运行线程

方法一:Thread创建线程方式:

  • 继承Thread类
  • 匿名内部类方式
public class CreateThread01 {

    public static void main(String[] args) {
        // 匿名内部类方式
        Thread t1 = new Thread("t1"){
            // run 方法内实现了要执行的任务
            public void run() {
                System.out.println("匿名内部类方式....."+ Thread.currentThread().getName());
            }
        };
        t1.start();
		
       	// 继承Thread类
        MyThread t2 = new MyThread();
        t2.start();
    }
}

class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("创建类继承Thread接口....." + Thread.currentThread().getName());
    }
}

方法二:实现Runnable配合Thread

  • 实现Runnale接口
  • 匿名内部类方式
public class CreateThread02 {

    public static void main(String[] args) {
        // 实现Runnale接口
        MyThread1 myThread1 = new MyThread1();
        Thread t1 = new Thread(myThread1);
        t1.start();

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类的方式....."+Thread.currentThread().getName());
            }
        };
        Thread t2 = new Thread(runnable);
        t2.start();
    }
}

// 实现Runnale接口
class MyThread1 implements Runnable{

    @Override
    public void run() {
        System.out.println("使用Runnable接口创建线程......"+ Thread.currentThread().getName());
    }
}

方式一和方式二的比较:

  • 开发中优先选择实现Runnable接口的方式
  • 原因:
    (1)实现的方式没有类的单继承性的局限性
    (2)实现的方式更适合来处理多个线程有共享数据的情况
  • 相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中

方法三:实现Callable接口

实现Callable接口:

  1. 定义一个线程任务类实现Callable接口,申明线程执行结果类型
  2. 重写Callable接口的call方法,这个方法可以直接返回执行结果
  3. 创建一个Callable的线程任务对象
  4. 把Callable的线程任务对象包装成一个未来任务对象
  5. 把未来任务对象包装成线程对象
  6. 调用线程的start()方法启动线程
  • public FutureTask(Callable<V> callable):未来任务对象,在线程执行完后得到线程的执行结果。

  • FutureTask就是Runnable对象,因为Thread类只能执行Runnable实例的任务对象,所以把Callable包装成未来任务对象

  • public V get():同步等待 task 执行完毕的结果,如果在线程中获取另一个线程执行结果,会阻塞等待,用于线程同步

    • get()线程会阻塞等待任务完成
    • run()执行完后会把结果设置到FutureTask的一个成员变量,get()线程可以获取到该变量的值
public class CreateThread03 {

    public static void main(String[] args)  {
        // 第一种将实现Callable接口类传入FutureTask
        FutureTask<String> task = new FutureTask<String>(new MyCallable());

        new Thread(task,"t3").start();
 		// 获取call方法返回的结果(正常/异常结果)
        String result = null;
        try {
            result = task.get();
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }


        // 第二种内部类实现
        FutureTask<String> task1 = new FutureTask<String>(() -> {
            return Thread.currentThread().getName() + "->" +"FutureTask";
        });
        new Thread(task1,"t4").start();
        try {
            result = task1.get();
            System.out.println(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyCallable implements Callable<String> {
    @Override  //重写线程任务类方法
    public String call() throws Exception {
        return Thread.currentThread().getName() + "->" +"实现Callable接口";
    }
}

优点:

  • 可以定义返回值

  • 可以抛出异常

方法四:利用线程池创建

使用 ThreadPoolExecutor 创建线程池,并从线程池中获取线程用于执行任务。在 JUC 中,Executor 框架已经实现了几种线程池,以 Executor 的 newFixedThreadPool 来作为 Demo 的展示。

public class CreateThread4 {
    public static void main(String[] args) throws ExecutionException,
            InterruptedException {
        System.out.println("----程序开始运行----");
        Date date1 = new Date();

        int taskSize = 5;
        // 创建一个线程池
        ExecutorService pool = Executors.newFixedThreadPool(taskSize);
        // 创建多个有返回值的任务
        List<Future> list = new ArrayList<Future>();
        for (int i = 0; i < taskSize; i++) {
            Callable c = new MyCallable1(i + " ");
            // 执行任务并获取Future对象
            Future f = pool.submit(c);
            // System.out.println(">>>" + f.get().toString());
            list.add(f);
        }
        // 关闭线程池
        pool.shutdown();

        // 获取所有并发任务的运行结果
        for (Future f : list) {
            // 从Future对象上获取任务的返回值,并输出到控制台
            System.out.println(">>>" + f.get().toString());
        }

        Date date2 = new Date();
        System.out.println("----程序结束运行----,程序运行时间【"
                + (date2.getTime() - date1.getTime()) + "毫秒】");
    }
}

class MyCallable1 implements Callable<Object> {
    private String taskNum;

    MyCallable1(String taskNum) {
        this.taskNum = taskNum;
    }

    public Object call() throws Exception {
        System.out.println(">>>" + taskNum + "任务启动");
        Date dateTmp1 = new Date();
        Thread.sleep(1000);
        Date dateTmp2 = new Date();
        long time = dateTmp2.getTime() - dateTmp1.getTime();
        System.out.println(">>>" + taskNum + "任务终止");
        return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】";
    }
}
  • ExecutorService、Callable、Future 实际上都是属于 Executor 框架。

  • 线程池支持有返回结果和无返回结果的任务,有返回值的任务必须实现Callable接口,无返回值的任务必须实现Runnable接口。

  • 对于有结果的任务,执行 Callable 任务后,可以获取一个 Future 的对象,在该对象上调用 get 就可以获取到Callable任务返回的 Object 了,

  • 但需要注意的是:get方法是阻塞的,如果线程未返回结果,那么 get() 方法会一直等待,直到有结果返回或者超时。

2.2 查看进程线程的方法

windows

- 任务管理器可以查看线程和进程数,也可以用来杀死进程
- tasklist      查看进程
- taskkill      杀死进程

linux

ps -fe    查看所有进程
ps -fT -p PID   查看某个进程(PID)的所有线程
kill    杀死进程
top     按大写H切换是否显示线程
top -H -p PID   查看某个进程(PID)的所有线程

Java

jps    查看所有java进程
jstack pid   查看某个java进程(Pid)的所有进程状态
jconsole   查看某个java进程中线程运行情况(图形界面)

jconsole 远程监控配置

  • 需要以如下方式运行你的 java 类

    java -Djava.rmi.server.hostname=`ip地址` -Dcom.sun.management.jmxremote -
    Dcom.sun.management.jmxremote.port=`连接端口` -Dcom.sun.management.jmxremote.ssl=是否安全连接 -
    Dcom.sun.management.jmxremote.authenticate=是否认证 java类
    
    
  • 修改/etc/hosts文件将127.0.0.1映射至主机名

  • 如果要认证

    • 复制 jmxremote.password 文件
    • 修改 jmxremote.password 和 jmxremote.access 文件的权限为 600 即文件所有者可读写
    • 连接时填入 controlRole(用户名),R&D(密码)

2.3原理之线程运行

栈与栈帧

Java Virtual Machine Stacks (Java 虚拟机栈)

​ JVM由堆、栈、方法去所组成,每个线程启动后,虚拟机就会为其分配一块栈内存

  • 每个栈由多个栈帧组成,对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

线程上下文切换

导致 cpu 不再执行当前的线程,转而执行另一个线程的代码原因:

  • 线程的cpu时间片用完
  • 垃圾回收
  • 有更高优先级的线程需要运行
  • 线程自己调用了sleep、yield、join、wait、park、synchronized、lock等方法

​ 当上下文切换(Context Switch发生时,需要由操作系统保存当前线程的状态,并恢复另一个线程的状态,Java中对应的概念就是程序计数器器(Program Counter Register),它的作用是记住下一条jvm指令的执行地址,是线程私有的。

  • 状态包括程序计数器、虚拟机中每个栈帧的信息,如局部变量、操作数栈、返回地址等
  • 线程上下文切换(Context Switch)频繁发生会影响性能

2.4 常用api以及详解

方法 说明
start() 启动一个新线程,Java虚拟机调用此线程的 run 方法
run() 线程启动后调用该方法
join() 等待线程运行结束
join(long n) 等待线程运行结束,最多等n毫秒
getId() 获得线程长整型id id是唯一的
getName() 获得线程名
getName(String name) 修改线程名
getPriority() 获得线程优先级
setPriority(int n) 修改线程优先级,java中规定线程优先级是1-10的整数,较大的优先级能提高该线程被CPU调度的几率,注意:这不是一定按照优先级的大小来进行调度的
getState() 获取线程的状态,Java 中线程状态是用 6 个 enum 表示,分别为: NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED
isInterrupted() 判断是否被打断,不会清楚打断标记
isAlive() 线程是否存活,即是否运行完毕
interrupt() 打断线程,如果打断线程正在sleep、wait、join中会导致被打断的线程抛出出 InterruptedException,并清除打断标记;如果被打断的是正在运行的线程,则会设置打断标记,则会设置打断标记;park线程被打断,也会设置打断标记
isInterrupt() 判断当前线程是否被打断,会清楚打断标记
currentThread() 获取当前正在执行的线程
sleep(long n) 让当前线程休眠n毫秒,休眠时让出cpu时间片给其他线程,睡眠结束后的线程未必会立刻得到执行
yield() 提示线程调度器让出当前线程对CPU的使用

start与run

  • 直接调用 run 是在主线程中执行了 run,没有启动新的线程
  • 使用 start 是启动新的线程,通过新的线程间接执行 run 中的代码

sleep与yield

sleep

  1. 调用 sleep 会让当前线程从 Running 进入 Timed Waiting 状态(阻塞)
  2. 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException
  3. 睡眠结束后的线程未必会立刻得到执行
  4. 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性

yield

  1. 调用yield会让当前线程从Running进入Runnable就绪状态,然后调度执行其他线程
  2. 具体实现依赖于操作系统的任务调度器

线程优先级

  • 线程优先级会提示(hint)调度器优先调度该线程,但仅仅是一个提示,调度器可以忽略。
  • 如果cpu比较忙,那么优先级高的线程会获得更多的时间片,但cpu闲时,优先级几乎没有作用

join方法

@Slf4j
public class ThreadJoinTest {

    static int r = 0;
    public static void main(String[] args) {
        test1();
    }

    private static void test1(){
        log.debug("开始");
        Thread t1 = new Thread(() -> {
            log.debug("开始");
            try {
                sleep(1);
                log.debug("结束");
                r = 10;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();
        log.debug("结束:{}",r);
        log.debug("结束");
    }
}


//注意: sleep用的是工具类
public class Sleeper {
    public static void sleep(int i) {
        try {
            TimeUnit.SECONDS.sleep(i);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void sleep(double i) {
        try {
            TimeUnit.MILLISECONDS.sleep((int) (i * 1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

打印结果为什么为0,而不是打印r=10 ?

  • 这个问题是因为主线程和t1线程是并行的,t1线程需要1秒才能算出r=10

  • 而主线程直接就打印出了r的值,所以只能打印出r=0

解决方法:

  • 我们能不能让主线程等待t1线程运行完,在打印出值。这就用到join()
@Slf4j
public class ThreadJoinTest {

    static int r = 0;
    public static void main(String[] args) throws InterruptedException {
        test1();
    }

    private static void test1() throws InterruptedException {
        log.debug("开始");
        Thread t1 = new Thread(() -> {
            log.debug("开始");
            try {
                sleep(1);
                log.debug("结束");
                r = 10;
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        t1.start();
        // 在主线程打印r值的前面加一个join,作用是等待t1线程运行完,在继续往下运行
        t1.join();
        log.debug("结束:{}",r);
        log.debug("结束");
    }
}

在这里插入图片描述

还有一个有时效的join方法

没等够时间

@Slf4j
public class ThreadJoinTest {

    static int r = 0;
    public static void main(String[] args) throws InterruptedException {
        test1();
    }

    private static void test1() throws InterruptedException {
        log.debug("开始");
        Thread t1 = new Thread(() -> {
            log.debug("开始");
            try {
                sleep(2);  // 睡2s
                log.debug("结束");
                r = 10;
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        t1.start();
        // 等1s
        t1.join(1000);
        log.debug("结束:{}",r);
        log.debug("结束");
    }
}

在这里插入图片描述

等够时间

@Slf4j
public class ThreadJoinTest {

    static int r = 0;
    public static void main(String[] args) throws InterruptedException {
        test1();
    }

    private static void test1() throws InterruptedException {
        log.debug("开始");
        Thread t1 = new Thread(() -> {
            log.debug("开始");
            try {
                sleep(2);  // 睡2s
                log.debug("结束");
                r = 10;
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        t1.start();
        // 等3s
        t1.join(3000);
        log.debug("结束:{}",r);
        log.debug("结束");
    }
}

在这里插入图片描述

interrupt方法

打断sleep线程

打断 sleep,wait,join 的线程

会让这几个线程都进入阻塞状态

打断sleep的线程,会清空打断标记

@Slf4j
public class InterruptTest01 {

    public static void main(String[] args) {
        Runnable r1 = (() -> {
            // sleep 导入工具类  现在是以秒为单位
            sleep(1);
        });
        Thread t1 = new Thread(r1,"t1");
        t1.start();
        sleep(0.5);
        t1.interrupt();
        log.debug("打断状态:{}",t1.isInterrupted());
    }
}

  • 打断sleep的线程会抛出InterruptedException异常
  • 并且清空打断标记

打断正常线程

打断正常运行的线程,不会清空打断标记

@Slf4j
public class InterruptTest02 {

    public static void main(String[] args) {
        Runnable r1 = (() -> {
           while(true){
               Thread currentThread = Thread.currentThread();
               boolean interrupted = currentThread.isInterrupted();
               if (interrupted){
                   log.debug("打断状态:{}",interrupted);
                   break;
               }
           }
        });
        Thread t1 = new Thread(r1,"t1");
        t1.start();
        sleep(0.5);
        t1.interrupt();
    }
}

在这里插入图片描述

注意:

  • 并不是说我打断这个正常运行的线程,他就停止了,如果光打断正常运行的线程,不判断打断状态的话,并不会停止,只是打断标记为true而已。

打断park线程

park: 暂停当前线程,处于 WAIT 状态

unpark: 既可以在 park 之前调用或之后调用,都是用来恢复某个线程的运行,简单的说,调用 unpark 后再调用 park 线程依然不会暂停,类似提前“解毒”。

打断 park 线程, 不会清空打断状态

@Slf4j
public class InterruptTest03 {
    public static void main(String[] args) {
        Runnable r1 = (() -> {
            log.debug("park....");
            LockSupport.park();
            log.debug("打断状态:{}",Thread.currentThread().isInterrupted());
        });
        Thread t1 = new Thread(r1,"t1");
        t1.start();

        sleep(0.5);
        t1.interrupt();
    }
}

在这里插入图片描述

注意:并不会停止运行,只是将打断标记设置为true

但是如果打断标记已经是true,则park将会失去作用

@Slf4j
public class InterruptTest03 {

    public static void main(String[] args) {
        Runnable r1 = (() -> {
            for (int i =0; i < 5; i++){
                log.debug("park....");
                LockSupport.park();
                log.debug("打断状态:{}",Thread.currentThread().isInterrupted());
            }
        });
        Thread t1 = new Thread(r1,"t1");
        t1.start();

        sleep(0.5);
        t1.interrupt();
    }
}

在这里插入图片描述

模式之两阶段终止

在一个线程t1中如何终止线程t2,并且能让t2在终止前,能有一个操作的机会。
在这里插入图片描述

利用isInterrupt()方法

interrupt 可以打断正在执行的线程,无论这个线程是在 sleep,wait,还是正常运行。

@Slf4j
public class InterrruptApplyTest {

    public static void main(String[] args) throws InterruptedException {
        TPTInterrupt t1 = new TPTInterrupt();
        t1.start();

        Thread.sleep(3500);
        log.debug("调用封装的stop");
        t1.stop();
    }
}

@Slf4j
class TPTInterrupt{

    private Thread thread;

    public void start(){
        thread = new Thread(()-> {
            while(true){
                Thread current = Thread.currentThread();
                if (current.isInterrupted()){
                    log.debug("最后的操作!");
                    break;
                }
                try {
                    // 这里的sleep并不是封装的 因为我们想让他抛出异常才能进行我们的下一步操作
                    sleep(1000);
                    log.debug("业务操作!");
                } catch (InterruptedException e) {
                    // 防止在睡的时候被主线程打断,我们在这里再次打断就可以继续运行
                    current.interrupt();
                }
            }
        },"工作线程");
        thread.start();
    }

    public void stop(){
        thread.interrupt();
    }
}
利用停止标记

volatile:保证了可见性、有序性

  • 保证此变量对所有线程的可见性,当一个线程修改了这个变量的值,volatile保证了新值能立即同步到主内存中,每次使用前从主内存中取值
  • 禁止指令重排序优化,这个操作相当于一个内存屏障,指令重排序时不能把后面的指令重排序到内存屏障之前的位置,在懒汉式的优化中也经常这样使用。
@Slf4j
public class InterrruptApplyTest {

    public static void main(String[] args) throws InterruptedException {
        TPTVolatile t1 = new TPTVolatile();
        t1.start();

        Thread.sleep(3500);
        log.debug("调用封装的stop");
        t1.stop();
    }
}

@Slf4j
class TPTVolatile{

    private Thread thread;
    // 停止标记用 volatile 是为了保证该变量在多个线程之间的可见
    // 主线程把它改成true,对t1线程可见
    private volatile boolean stop = false;

    public void start(){
        thread = new Thread(()-> {
            while(true){
                Thread current = Thread.currentThread();
                if (stop){
                    log.debug("最后的操作!");
                    break;
                }
                try {
                    // 这里的sleep并不是封装的 因为我们想让他抛出异常才能进行我们的下一步操作
                    sleep(1000);
                    log.debug("业务操作!");
                } catch (InterruptedException e) {
                    // 防止在睡的时候被主线程打断,我们在这里再次打断就可以继续运行
                    current.interrupt();
                }
            }
        },"工作线程");
        thread.start();
    }

    public void stop(){
        stop = true;
    }
}

在这里插入图片描述

加粗样式

2.5 主线程和守护线程

默认情况下,Java进程需要等待所有线程都运行结束,才会结束,有一种特殊线程叫做守护线程,只要其他非守护线程运行结束了,即使守护线程里的代码没执行完,也会强制结束。

@Slf4j
public class GuardThreadTest {

    public static void main(String[] args) {
        log.debug("开始运行...");
        Thread t1 = new Thread(() -> {
            log.debug("开始运行....");
            // 2s后
            sleep(2);
            log.debug("运行结束....");
        },"daemon");

        // 设置该线程是守护线程
        t1.setDaemon(true);
        t1.start();

        sleep(1);
        log.debug("运行结束...");
    }
}

在这里插入图片描述

主线程结束后,守护线程并没有执行 运行结束

  • 垃圾回收器线程就是一种守护线程
  • Tomcat中的Acceptor和Poller线程都是守护线程,所以Tomcat接收到shutdown命令后,不会等待它门处理完当前请求

2.6五种状态

操作系统层面

  • 初始状态 仅仅是在语言层面创建了线程对象,还未与操作系统的线程关联
  • 可运行状态 (就绪状态) 指线程已经被创建(与操作系统的线程关联),可以由CPU调度执行
  • 运行状态 指已获取了CPU时间片运行中的状态
  • 阻塞状态
    • 如果调用了阻塞API,如BIO读写文件,这时该线程实际不会用到CPU,会导致线程上下文切换,进入阻塞状态
    • 等BIO操作完,会由操作系统唤醒阻塞的线程,转换至 可运行状态
    • 可运行状态的区别是,对 阻塞状态的线程来说只要一直不唤醒,调度器就一直不会考虑调度它们
  • 终止状态表示线程已经执行完毕,生命周期已经结束,不会再转换为奇它状态

2.7六种状态

Java层面 根据 Thread.State 枚举,分为六种状态

在这里插入图片描述

  • NEW 线程刚被创建,但是还没调用start()方法
  • RUNNABLE 当调用了start()方法之后,在Java API层面的 RUNNABLE状态涵盖了操作系统层面的 可运行状态运行状态阻塞状态(由于BIO导致的线程阻塞,在Java里无法区分,仍然认为是可运行)
  • BLOCKEDWAITINGTIME_WAITING都是Java API层面对 阻塞状态的细分
  • TERMINATED当线程代码运行结束
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JUC并发编程之Java线程(二) 的相关文章

  • 获取jdbc中表依赖顺序

    我在 MySQL 数据库中有一组表 A B C D 依赖关系如下 B gt C gt A 和 D gt A 也就是说 A 有一个 PrimaryKey C 有一个外键指向 A 的主键 B 有一个外键指向 C 的主键 类似地 D 有一个外键指
  • 如何降低圈复杂度?

    我正在开发一个将 RequestDTO 发送到 Web 服务的类 我需要在发送请求之前验证该请求 请求可以从 3 个不同的地方发送 并且每个 请求类型 有不同的验证规则 例如请求1必须有姓名和电话号码 请求2必须有地址等 我有一个 DTO
  • JAX-WS:有状态 WS 在独立进程中失败

    我在 Tomcat 上部署了一个有状态的 Web 服务 它由工厂服务和主要 API 服务组成 并且工作得很好 工厂服务将 W3CEndpointReference 返回到主 API 实例 客户端使用会话 现在 我尝试将相同的服务作为独立应用
  • BigDecimal 的 JPA @Size 注释

    我该如何使用 SizeMySQL 的注释DECIMAL x y 列 我在用着BigDecimal 但是当我尝试包括 Size max它不起作用 这是我的代码 Size max 7 2 Column name weight private B
  • 用于防止滥用的 Servlet 过滤器? (DoS、垃圾邮件等)

    我正在寻找一个 Servlet 过滤器库 它可以帮助我保护我们的 Web 服务免受未经授权的使用和 DDoS 攻击 我们的网络服务有 授权客户 因此理想情况下 过滤器将帮助检测未经授权或行为不当的客户 或检测使用同一帐户的多个人 此外 我们
  • Scala(或 Java)中泛型函数的特化

    是否可以在 Scala 中专门化泛型函数 或类 例如 我想编写一个将数据写入 ByteBuffer 的通用函数 def writeData T buffer ByteBuffer data T buffer put data 但由于 put
  • 如何将txt文件添加到你的android项目中? [复制]

    这个问题在这里已经有答案了 我的Android studio版本是1 5 1 显然这个 never 版本没有 txt 文件的 asset 文件夹 您打算如何将这些文件包含到您的项目中 以及如何进一步使用您内部的应用程序 谢谢你的建议 Pro
  • Kerberos 缓存票证

    我使用的是 Windows 7 64 位 我创建了一个简单的应用程序来对实现 PrivilegedAction 的类的 run 方法中的文件进行计数 以下是我的 jaas conf 文件 CountFiles com sun securit
  • 尝试在空对象引用上调用虚拟方法“java.lang.String org.jsoup.nodes.Element.ownText()”

    我正在使用下面的代码来获取版本名称 from 应用商店通过使用 jsoup 我正在获取详细信息 但它引发了一些异常 我的代码是 public class ForceUpdateAsync extends AsyncTask
  • 在多模块项目中访问绑定适配器

    我有一个多模块项目 其中应用程序模块包含我的绑定适配器 而我的功能模块取决于我的应用程序模块 因为它是动态功能模块 应用程序 包含绑定适配器 gt 动态功能模块 存在布局的地方 我在所有模块中启用了数据绑定和 kapt 我无法成功构建应用程
  • NoSuchMethodError:将 Firebase 与应用程序引擎应用程序集成时

    我试图将 firebase 实时数据库与谷歌应用程序引擎应用程序集成 我在调用时收到此错误 gt DatabaseReference ref FirebaseDatabase gt getInstance gt getReference t
  • 删除 ArrayList 对象问题

    我在处理作业时遇到从 ArrayList 中删除对象的问题 如果我使用 正常 for 循环 它的工作原理如下 public void returnBook String isbn for int i 0 i lt booksBorrowed
  • 如何列出所有可用的 LookAndFeel 主题?

    如何列出所有可用的 LookAndFeel 主题 我想在 JComboBox 中显示以供用户选择 这真的很简单 public static UIManager LookAndFeelInfo getInstalledLookAndFeels
  • Hibernate @OneToMany 注释到底是如何工作的?

    我对 Hibernate 还很陌生 我正在通过教程学习它 我在理解到底如何一对多注释作品 所以我有这两个实体类 Student代表一个学生并且Guide代表指导学生的人 因此 每个学生都与一名向导相关联 但一名向导可以跟随多个学生 我想要一
  • C++ 中的 Java ArrayList [重复]

    这个问题在这里已经有答案了 在Java中我可以做 List
  • 为什么 RMI 注册表忽略 java.rmi.server.codebase 属性

    我正在运行 java RMI 的 Hello World 示例 1 我在空文件夹中运行注册表 motta motta laptop tmp rmiregistry 2 我启动 HTTP 服务器以在运行时检索类 下载文件夹包含客户端 服务器的
  • 无法仅在控制台中启动 androidstudio

    你好 我的问题是下一个 我下载了Android Studio如果我去 路径 android studio bin 我执行studio sh 我收到以下错误 No JDK found Please validate either STUDIO
  • setKeyListener 将覆盖 setInputType 并更改键盘

    大家好 我在两个设备之间遇到问题 在实践中使用InputType和KeyListener我正在操纵一个EditText让它从数字键盘接收逗号和数字 有关更多背景信息 请检查我之前的question https stackoverflow c
  • 如何使用maven创建基于spring的可执行jar?

    我有一个基于 Maven 的 Spring WS 客户端项目 我想将其打包为单个 jar 在eclipse中 一切运行正常 当我尝试将其打包为可执行 jar 时 我收到 ClassNotFound 异常 因为 Spring jar 未包含在
  • JPA - 非主键字段上的 @OneToOne 关系不起作用

    我有一个 Spring Data JPA 后端 使用 Hibernate 作为 ORM 实现 这是模型 Person MailConfig id PK uid PK FK Person uid uid Entity

随机推荐

  • hj212协议如何和php通讯,HJ212数据传输标准报文解析

    HJ212分为2005年 HJ T212 2005 和2017年 HJ212 2017 的版本 略有不同 网上没找到非常官方的渠道下载 在这贴一份2017年版本的下载地址 TCP IP通讯包组成 名称 类型 长度 描述 包头 字符 2 固定
  • 有符号数和无符号数

    1 数值 针对二进制来讲 有 有符号数 signed 和无符号数 unsigned 因为计算机无法区分一个二进制数是有符号数还是无符号数 因此我们在定义时要明确该数值是有符号数还是无符号数 无符号类型需要通过unsigned关键字指定 否则
  • 下载bison和flex的好地方

    http sourceforge net projects gnuwin32 这里的bison和flex我觉得是最好用的 捣乱的
  • vue el-form-item给多个表单项绑定rules校验规则

    vue el form item给多个表单项绑定rules规则 如图所示 我们想要在element的表单里 给多个input添加校验规则 只需要在内部添加el form item项 并在el form item项里绑定prop和rules规
  • 基于Prompt的MLM文本分类

    简介 常规NLP做文本分类时常用Transfer Learning的方式 在预训练bert上加一个分类层 哪个输出节点概率最大则划分到哪一类别 而基于Prompt的MLM文本分类是将文本分类任务转化为MLM Masked Language
  • 自动驾驶前沿综述:基于深度强化学习的自动驾驶算法

    作者 TIM 编辑 汽车人 原文链接 https zhuanlan zhihu com p 477372894 点击下方卡片 关注 自动驾驶之心 公众号 ADAS巨卷干货 即可获取 点击进入 自动驾驶之心技术交流群 后台回复 数据集下载 获
  • python弹窗程序教程(附源码解析)

    python弹窗程序教程 附源码解析 声明 此程序仅供娱乐整蛊 使用者后果自负 本人概不负责 代码可能有雷同 如有侵权 请联系小编 引言 弹窗是程序的一种显示内容的形式 例如警告 提示等 而弹窗还有一种特殊的呈现形式 恶意程序 有人说不就是
  • VUE3写后台管理(3)

    VUE3写后台管理 3 1 环境 1 node 2 vite 3 Element plus 4 vue router 5 element icon 6 less 7 vuex 8 vue demi 9 mockjs 10 axios 11
  • Top 5 Best Open Source Projects on GitHub 2023

    这里介绍Github上 5 个增长最快的开源项目 它们为原有的解决方案提供了更加具有成本效益的替代方案 并为开发者 数据分析师和企业提供了高可用的工具产品 利用开源的优势 这5个项目拓展了强大而有效的解决方案 是值得收藏 分享以及探索尝试的
  • wayland 概述

    wayland 背景 强烈推荐在阅读本文前先浏览以下文档 Wayland Architecture 概述 wayland 是一种用于用于显示服务器的协议 它规定了客户端如何与服务器进行通信 也就是说 wayland 仅仅只是标准化 了客户端
  • 数据太大,long放不下的问题。numberOutOf Range

    数据库返回的数据 long存不下 改为用String类型
  • 缺失值填充5——AutoEncoder填充序列缺失值

    AutoEncoder可以参考 pytorch实现基本AutoEncoder与案例 AutoEncoder填充缺失值的思路是 在完整的数据集上训练一个AutoEncoder 把有缺失的数据拿过来 先全零填充原有的值 再通过AutoEncod
  • Eigen库 矩阵基本操作:转置矩阵,逆矩阵,伴随矩阵,特征值

    include
  • WebLogic 之安全配置

    WebLogic 之安全配置 前段时间Java的反序列化漏洞吵得沸沸扬扬 因工作原因需要对weblogic进行安全配置 网上关于weblogic的安全配置的内容都不是很全面 可能是因为weblogic已经比较成熟了吧 本文就总结一下在整个过
  • 仿射变换原理和其OpenCV-Python实现知识汇总

    老猿Python博文目录 https blog csdn net LaoYuanPython 一 仿射变换概念和类型 图像几何变换又称为图像空间变换 是各种图像处理算法的基础 它是在不改变图像内容的情况下 对图像像素进行空间几何变换的处理方
  • UAV无人机(三):飞控系统

    无人机的飞控系统是指控制和管理无人机飞行的核心组件 它主要负责飞行姿态控制 导航 稳定性控制 传感器数据处理和通信等功能 以下是无人机飞控系统的一般组成部分 主控制器 Flight Controller 主控制器是飞控系统的核心 通常是一个
  • java中的example_Java中mybatis关于example类的使用详解

    这几天刚接触example 很多内容都是破碎的 写一篇博文加深理解 一 什么是example类 mybatis generator会为每个字段产生如上的Criterion 如果表的字段比较多 产生的Example类会十分庞大 理论上通过ex
  • js中常见的数据加密与解密的方法

    加密在我们前端的开发中也是经常遇见的 本文只把我们常用的加密方法进行总结 不去纠结加密的具体实现方式 密码学 太庞大了 常见的加密方式 常见的加密算法基本分为这几类 线性散列算法 签名算法 MD5 SHA1 对称性加密算法 AES DES
  • Linux的安装与卸载软件

    目录 rpm yum 源码包 1 rpm 1 rpm简介 rpm工具 Redhat package management 2 rpm工具使用 a 设置光驱并挂载 我们先上传我们的iso文件到虚拟机里 确认好已经上传完了之后我们输入命令 mo
  • JUC并发编程之Java线程(二)

    二 Java线程 2 1 创建和运行线程 方法一 Thread创建线程方式 继承Thread类 匿名内部类方式 public class CreateThread01 public static void main String args