Java多线程深入探讨

    • 1. 线程与进程
    • 2. 创建和管理线程
      • 2.1. 继承Thread类
      • 2.2. 实现Runnable接口
      • 2.3 利用Callable、FutureTask接口实现。
      • 2.4 Thread的常用方法
    • 3. 线程同步
      • 3.1. synchronized关键字
        • 3.1.1同步代码块:
        • 3.1.2 同步方法:
      • 3.2. Lock接口
    • 4. 线程间通信
    • 5. 线程池
      • 5.1 使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象
      • 5.2 使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象
    • 6. Java并发工具类
      • 6.1. CountDownLatch
      • 6.2. CyclicBarrier
      • 6.3. Semaphore
      • 6.4. ConcurrentHashMap
      • 6.5. BlockingQueue
    • 7. 总结
    • 9. 线程优先级
    • 10. 守护线程
    • 11. 线程局部变量
    • 12. 线程异常处理
    • 13. 实践建议

Java多线程编程是Java程序员必备的技能之一,因为它可以帮助我们编写更高效、更快速的程序。在本文中,我们将深入探讨Java多线程的基本概念、线程的创建和管理、同步、线程池以及Java并发工具类。

1. 线程与进程

进程是操作系统进行资源分配的基本单位,它是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,它是系统进行资源分配和调度的一个独立单位。

线程是进程中的一个实体,它是被操作系统独立调度和执行的基本单位。一个进程中可以有多个线程,这些线程共享进程的资源,如内存、文件句柄等。线程之间的切换比进程切换要快得多,因为线程间通信成本更低。

2. 创建和管理线程

在Java中,有两种方法可以创建线程:(还有JDK5新增了一种方法:实现Callable接口)

2.1. 继承Thread类

步骤:

①定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法

②创建MyThread类的对象

③调用线程对象的start()方法启动线程(启动后还是执行run方法的)

创建一个新类,该类继承自Thread类,然后覆盖run方法:

class MyThread extends Thread {
    @Override
    public void run() {
        // 你的线程代码
    }
}

// 在主程序中创建并启动线程:
MyThread myThread = new MyThread();
myThread.start();

优缺点:

  • 优点:编码简单
  • 缺点:存在单继承的局限性,线程类继承Thread后,不能继承其他类,不便于扩展

注意:

1、为什么不直接调用了run方法,而是调用start启动线程。

  • ​ 直接调用run方法会当成普通方法执行,此时相当于还是单线程执行。
  • ​ 只有调用start方法才是启动一个新的线程执行。

2、把主线程任务放在子线程之前了。

  • 这样主线程一直是先跑完的,相当于是一个单线程的效果了。

2.2. 实现Runnable接口

步骤:

①定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法

②创建MyRunnable任务对象

③把MyRunnable任务对象交给Thread处理。

④调用线程对象的start()方法启动线程

创建一个新类,实现Runnable接口,然后实现run方法:

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 你的线程代码
    }
}

// 在主程序中创建并启动线程:
Thread thread = new Thread(new MyRunnable());
thread.start();

实现Runnable接口通常是更好的选择,因为它允许你的类继承其他类,而Java不支持多继承。

优缺点:

  • 优点:线程任务类只是实现了Runnale接口,可以继续继承类和实现接口,扩展性强。
  • 缺点:编程多一层对象包装,如果线程有执行结果是不可以直接返回的。

Thread的构造器

构造器说明
public Thread(String name)可以为当前线程指定名称
public Thread(Runnable target)封装Runnable对象成为线程对象
public Thread(Runnable target ,String name )封装Runnable对象成为线程对象,并指定线程名称

2.3 利用Callable、FutureTask接口实现。

前言:

1、前2种线程创建方式都存在一个问题:

  • 他们重写的run方法均不能直接返回结果。
  • 不适合需要返回线程执行结果的业务场景。

2、怎么解决这个问题呢?

  • JDK 5.0提供了Callable和FutureTask来实现。
  • 这种方式的优点是:可以得到线程执行的结果。

步骤:

①、得到任务对象

​ 1.定义类实现Callable接口,重写call方法,封装要做的事情。

​ 2.用FutureTask把Callable对象封装成线程任务对象。

②、把线程任务对象交给Thread处理。

③、调用Thread的start方法启动线程,执行任务

④、线程执行完毕后、通过FutureTask的get方法去获取任务执行的结果。

FutureTask的API

方法名称说明
public FutureTask<>(Callable call)把Callable对象封装成FutureTask对象。
public V get() throws Exception获取线程执行call方法返回的结果。

优缺点:

  • 优点:线程任务类只是实现接口,可以继续继承类和实现接口,扩展性强。
  • 可以在线程执行完毕后去获取线程执行的结果。
  • 缺点:编码复杂一点。

总结:

方式优点缺点
继承Thread类编程比较简单,可以直接使用Thread类中的方法扩展性较差,不能再继承其他的类,不能返回线程执行的结果
实现Runnable接口扩展性强,实现该接口的同时还可以继承其他的类。编程相对复杂,不能返回线程执行的结果
实现Callable接口扩展性强,实现该接口的同时还可以继承其他的类。可以得到线程执行的结果编程相对复杂

2.4 Thread的常用方法

Thread常用方法:获取线程名称getName()、设置名称setName()、获取当前线程对象currentThread()。

  1. 当有很多线程在执行的时候,我们怎么去区分这些线程呢?

此时需要使用Thread的常用方法:getName()、setName()、currentThread()等。

Thread获取和设置线程名称

方法名称说明
String getName()获取当前线程的名称,默认线程名称是Thread-索引
void setName(String name)将此线程的名称更改为指定的名称,通过构造器也可以设置线程名称

Thread类获得当前线程的对象

方法名称说明
public static Thread currentThread():返回对当前正在执行的线程对象的引用

注意:

1、此方法是Thread类的静态方法,可以直接使用Thread类调用。 2、这个方法是在哪个线程执行中调用的,就会得到哪个线程对象。

Thread类的线程休眠方法

方法名称说明
public static void sleep(long time)让当前线程休眠指定的时间后再继续执行,单位为毫秒。

3. 线程同步

在多线程环境下,如果多个线程同时访问共享资源,可能会导致数据不一致的问题。为了解决这个问题,我们需要对共享资源进行同步。

线程同步的核心思想

  • 加锁,把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来。

3.1. synchronized关键字

在Java中,我们可以使用synchronized关键字来实现同步。synchronized可以修饰方法或者代码块。当一个线程进入synchronized修饰的方法或代码块时,其他线程将被阻塞,直到该线程离开。

以下是一个使用synchronized关键字的示例:

class Counter {
    private int count;

    public synchronized void increment() {
        count++;
    }

    public synchronized void decrement() {
        count--;
    }

    public synchronized int getCount() {
        return count;
    }
}

3.1.1同步代码块:

作用:把出现线程安全问题的核心代码给上锁。

原理:每次只能一个线程进入,执行完毕后自动解锁,其他线程才可以进来执行。
在这里插入图片描述

锁对象要求

  • 理论上:锁对象只要对于当前同时执行的线程来说是同一个对象即可。

锁对象的规范要求

  • 规范上:建议使用共享资源作为锁对象。

  • 对于实例方法建议使用this作为锁对象。

  • 对于静态方法建议使用字节码(类名.class)对象作为锁对象。

3.1.2 同步方法:

作用:把出现线程安全问题的核心方法给上锁。
原理:每次只能一个线程进入,执行完毕以后自动解锁,其他线程才可以进来执行。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6qAe9eag-1682872681762)(C:\Users\28333\AppData\Roaming\Typora\typora-user-images\image-20230501002606877.png)]

原理:

  • 同步方法其实底层也是有隐式锁对象的,只是锁的范围是整个方法代码。
  • 如果方法是实例方法:同步方法默认用this作为的锁对象。但是代码要高度面向对象!
  • 如果方法是静态方法:同步方法默认用类名.class作为的锁对象。

3.2. Lock接口

除了使用synchronized关键字外,Java还提供了java.util.concurrent.locks包中的Lock接口,该接口允许我们实现更灵活、更细粒度的同步。ReentrantLockLock接口的一个实现,它允许线程以可重入的方式获取锁。

以下是一个使用ReentrantLock的示例:

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

class Counter {
    private int count;
    private Lock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public void decrement() {
        lock.lock();
        try {
            count--;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }
}

4. 线程间通信

线程间通信是指多个线程之间互相发送消息或数据的过程。在Java中,我们可以使用waitnotifynotifyAll方法实现线程间通信。

线程通信常见形式

  • 通过共享一个数据的方式实现。
  • 根据共享数据的情况决定自己该怎么做,以及通知其他线程怎么做。

应用场景:

  • 生产者与消费者模型:生产者线程负责生产数据,消费者线程负责消费生产者产生的数据。

  • 要求:生产者线程生产完数据后唤醒消费者,然后等待自己,消费者消费完该数据后唤醒生产者,然后等待自己。

方法名称说明
void wait()让当前线程等待并释放所占锁,直到另一个线程调用notify()方法或 notifyAll()方法
void notify()唤醒正在等待的单个线程
void notifyAll()唤醒正在等待的所有线程

以下是一个使用waitnotify实现生产者消费者模型的示例:

import java.util.LinkedList;
import java.util.Queue;

public class ProducerConsumerExample {
    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        int maxSize = 10;

        Thread producer = new Thread(new Producer(queue, maxSize), "Producer");
        Thread consumer = new Thread(new Consumer(queue), "Consumer");

        producer.start();
        consumer.start();
    }
}

class Producer implements Runnable {
    private Queue<Integer> queue;
    private int maxSize;

    public Producer(Queue<Integer> queue, int maxSize) {
        this.queue = queue;
        this.maxSize = maxSize;
    }

    @Override
    public void run() {
        int value = 0;
        while (true) {
            synchronized (queue) {
                while (queue.size() == maxSize) {
                    try {
                        queue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                System.out.println("Producing " + value);
                queue.add(value++);
                queue.notifyAll();
            }
        }
    }
}

class Consumer implements Runnable {
    private Queue<Integer> queue;

    public Consumer(Queue<Integer> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (queue) {
                while (queue.isEmpty()) {
                    try {
                        queue.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                int value = queue.poll();
                System.out.println("Consuming " + value);
                queue.notifyAll();
            }
        }
    }
}

5. 线程池

线程池是一种管理线程的机制,它允许我们重用线程以减少创建和销毁线程的开销。在Java中,我们可以使用ExecutorService接口和Executors类来创建和管理线程池。

5.1 使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象

ExecutorService
ThreadPoolExecutor

ThreadPoolExecutor构造器的参数说明
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-99K71aWk-1682872681763)(C:\Users\28333\AppData\Roaming\Typora\typora-user-images\image-20230501003214497.png)]

注:

临时线程什么时候创建啊?

新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程。

什么时候会开始拒绝任务?

核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始任务拒绝。

ExecutorService的常用方法

方法名称说明
void execute(Runnable command)执行任务/命令,没有返回值,一般用来执行 Runnable 任务
Future submit(Callable task)执行任务,返回未来任务对象获取线程结果,一般拿来执行 Callable 任务
void shutdown()等任务执行完毕后关闭线程池
List<Runnable]> shutdownNow()立刻关闭,停止正在执行的任务,并返回队列中未执行的任务

5.2 使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象

Executors得到线程池对象的常用方法

  • Executors:线程池的工具类通过调用方法返回不同类型的线程池对象。
方法名称说明
public static ExecutorService newCachedThreadPool()线程数量随着任务增加而增加,如果线程任务执行完毕且空闲了一段时间则会被回收掉。
public static ExecutorService newFixedThreadPool(int nThreads)创建固定线程数量的线程池,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程替代它。
public static ExecutorService newSingleThreadExecutor ()创建只有一个线程的线程池对象,如果该线程出现异常而结束,那么线程池会补充一个新线程。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)创建一个线程池,可以实现在给定的延迟后运行任务,或者定期执行任务。

以下是一个使用线程池的示例:

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

public class ThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 10; i++) {
            Runnable worker = new WorkerThread("" + i);
            executorService.execute(worker);
        }

        executorService.shutdown();

        while (!executorService.isTerminated()) {
        }

        System.out.println("All threads finished");
    }
}

class WorkerThread implements Runnable {
    private String message;

    public WorkerThread(String message) {
        this.message = message;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " processing message: " + message);
        processMessage();
    }

    private void processMessage() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

6. Java并发工具类

Java并发包java.util.concurrent提供了许多并发工具类,它们可以帮助我们简化多线程编程。以下是一些常用的并发工具类:

6.1. CountDownLatch

CountDownLatch允许一个或多个线程等待其他线程完成操作。它包含一个初始计数值,任何调用await方法的线程都将被阻塞,直到计数值为0。

6.2. CyclicBarrier

CyclicBarrier允许一组线程相互等待,直到所有线程都到达某个屏障点。当最后一个线程到达屏障点时,所有等待的线程将被释放。

6.3. Semaphore

Semaphore用于限制可以访问某个资源的线程数量。当一个线程要访问受限资源时,需要先获得信号量;当线程完成操作时,释放信号量。如果没有可用的信号量,线程将阻塞,直到有线程释放信号量。

6.4. ConcurrentHashMap

ConcurrentHashMap是一个线程安全的HashMap实现,它允许多个线程并发访问。与使用synchronized关键字的HashMap相比,它具有更好的性能。

6.5. BlockingQueue

BlockingQueue是一个阻塞队列,它支持线程安全的插入和删除操作。当队列为空时,删除操作将阻塞;当队列满时,插入操作将阻塞。BlockingQueue在生产者-消费者模型中非常有用。

7. 总结

本文深入探讨了Java多线程编程的基本概念、线程的创建和管理、同步、线程池以及Java并发工具类。了解这些概念和技术对于编写高效、高性能的Java程序至关重要。希望本文能为你的Java多线程编程之旅提供有用的指导!## 8. 线程的状态和生命周期

在Java中,线程具有以下状态:

  1. 新建(New):当我们创建了一个线程对象,但还没有调用start()方法时,线程处于新建状态。
  2. 就绪(Runnable):当线程对象调用了start()方法后,线程进入就绪状态。在这个状态下,线程已经准备好运行,等待操作系统分配时间片。
  3. 运行(Running):线程获得时间片并开始执行run()方法中的代码时,线程处于运行状态。
  4. 阻塞(Blocked):线程在等待获取锁以进入同步代码块或方法时,线程进入阻塞状态。
  5. 等待(Waiting):线程在等待其他线程执行特定操作(如调用notify()notifyAll()方法)时,线程进入等待状态。例如,线程调用了Object.wait()Thread.join()LockSupport.park()方法。
  6. 超时等待(Timed Waiting):线程在等待其他线程执行特定操作,但最多等待指定的时间。例如,线程调用了Thread.sleep()Object.wait(long timeout)LockSupport.parkNanos()方法。
  7. 终止(Terminated):线程完成了run()方法的执行或因异常而终止,线程进入终止状态。

要获取线程的当前状态,可以调用Thread.getState()方法。

9. 线程优先级

在Java中,线程具有优先级。优先级较高的线程可能会比优先级较低的线程获得更多的执行时间。线程优先级是通过Thread.setPriority(int)方法设置的,取值范围为1到10,其中1表示最低优先级,10表示最高优先级。可以使用Thread.getPriority()方法获取线程的当前优先级。

需要注意的是,线程优先级并不能保证线程执行的顺序,它只是影响线程获得执行时间的可能性。因此,在编写多线程程序时,不应依赖线程优先级来实现正确的同步或顺序。

10. 守护线程

守护线程(Daemon Thread)是一种特殊类型的线程,主要用于在后台为其他线程提供服务。当所有非守护线程结束时,守护线程会自动结束。垃圾回收线程就是一个典型的守护线程。

要将线程设置为守护线程,可以在调用start()方法之前调用Thread.setDaemon(true)方法。可以使用Thread.isDaemon()方法检查线程是否为守护线程。

注意:不要将可能与其他线程进行交互的线程设置为守护线程,因为守护线程可能会在任何时候终止。如果守护线程在与其他线程交互时突然终止,可能会导致不可预测的行为或数据不一致。

11. 线程局部变量

线程局部变量(Thread-Local Variables)是一种特殊类型的变量,它为每个线程提供独立的变量副本。这意味着每个线程可以访问和修改它自己的变量副本,而不会影响其他线程的副本。

Java中提供了ThreadLocal类来实现线程局部变量。要创建一个线程局部变量,可以创建一个ThreadLocal对象,并调用get()set(T value)方法来获取和设置线程的变量副本。以下是一个使用ThreadLocal的示例:

public class ThreadLocalExample {
    private static ThreadLocal<Integer> threadLocalCounter = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    int counter = threadLocalCounter.get();
                    threadLocalCounter.set(counter + 1);
                    System.out.println("Thread-1: " + threadLocalCounter.get());
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    int counter = threadLocalCounter.get();
                    threadLocalCounter.set(counter + 1);
                    System.out.println("Thread-2: " + threadLocalCounter.get());
                }
            }
        });

        t1.start();
        t2.start();
    }
}

在这个示例中,threadLocalCounter是一个线程局部变量。我们为每个线程提供了初始值0。当每个线程执行时,它们都会访问和修改自己的计数器副本,而不会影响其他线程的副本。

12. 线程异常处理

当线程抛出未捕获的异常时,Java提供了一种机制来处理这些异常。可以通过实现Thread.UncaughtExceptionHandler接口并调用Thread.setDefaultUncaughtExceptionHandler()方法来设置全局的未捕获异常处理器。此外,还可以通过调用Thread.setUncaughtExceptionHandler()方法为单个线程设置未捕获异常处理器。

以下是一个设置未捕获异常处理器的示例:

public class ThreadExceptionHandlingExample {
    public static void main(String[] args) {
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println(t.getName() + " throws exception: " + e);
            }
        });

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(1 / 0);
            }
        }, "Thread-1");

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                throw new RuntimeException("An exception occurred in Thread-2");
            }
        }, "Thread-2");

        t1.start();
        t2.start();
    }
}

在这个示例中,我们设置了一个全局的未捕获异常处理器,用于处理所有线程抛出的未捕获异常。当Thread-1Thread-2抛出未捕获的异常时,异常处理器会捕获并处理这些异常。

13. 实践建议

在进行多线程编程时,以下是一些建议和注意事项:

  1. 尽量使用java.util.concurrent包中提供的高级并发工具类,而不是直接使用Threadsynchronized关键字。这可以简化代码并提高程序的可维护性和性能。
  2. 在编写多线程程序时,避免使用全局变量或共享状态,以降低同步的复杂性和可能出现的错误。
  3. 要充分利用Java的内存模型,确保线程之间正确地共享和同步数据。
  4. 使用线程池来管理和调度线程,以提高程序性能。
  5. 避免线程优先级来实现正确的同步或顺序,因为它不能保证线程执行的顺序。
  6. 使用守护线程为其他线程提供后台服务,但不要将可能与其他线程进行交互的线程设置为守护线程。
  7. 当需要为每个线程提供独立的变量副本时,使用线程局部变量。
  8. 为线程设置未捕获异常处理器,以便在线程抛出未捕获的异常时进行处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/16756.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】管道

目录 一、前言 二、管道 1、匿名管道 1.1、基本原理 1.2、代码实现 1.3、管道的特点 1.4、基于管道的简单设计 2、命名管道 2.1、匿名管道与命名管道的区别 2.2、代码实现命名管道通信 一、前言 为了满足各种需求&#xff0c;进程之间是需要通信的。进程间通信的主要目…

python函数的递归调用

引入 函数既可以嵌套定义也可以嵌套调用。嵌套定义指的是在定义一个函数时在该函数内部定义另一个函数&#xff1b;嵌套调用指的是在调用一个函数的过程中函数内部有调用另一个函数。而函数的递归调用指的是在调用一个函数的过程中又直接或者间接的调用该函数本身。 函数递归…

PySpark基础入门(3):RDD持久化

RDD的持久化 RDD 的数据是过程数据&#xff0c;因此需要持久化存储&#xff1b; RDD之间进行相互迭代的计算&#xff0c;新的RDD的生成代表着旧的RDD的消失&#xff1b;这样的特性可以最大化地利用资源&#xff0c;老旧地RDD可以及时地从内存中清理&#xff0c;从而给后续地计…

aop切面调用失效问题排查

应用里有较多的地方访问外部供应商接口&#xff0c;由于公网网络不稳定或者外部接口不稳定&#xff08;重启&#xff0c;发版&#xff0c;ip切换&#xff09;的原因&#xff0c;经常报502或者504错误。为了解决HTTP调用的500报错&#xff0c;选择使用spring的retryable注解进行…

Pyinstaller将python文件打包成exe程序——封装LoFTR开源匹配代码

Pyinstaller将python文件打包成exe程序——封装LoFTR开源匹配代码 1.LoFTR代码下载及环境搭建 源码下载&#xff1a;https://github.com/bodhisatan/LoFTR-Stitch 环境搭建&#xff1a;按照github项目中的readme文档进行搭建即可&#xff0c;几乎没有遇到问题&#xff0c;代码…

【Unity入门】22.动态创建实例

【Unity入门】动态创建实例 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity入门系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;一&#xff09;脚本实例化预制体对象 &#xff08;1&#xff09;Instantiate克隆创建对象 昨天我们学习了预制体这个概念&#…

文献阅读(50)—— Transformer 用于肺癌诊断预测

文献阅读&#xff08;50&#xff09;—— Transformer 用于肺癌诊断预测 文章目录 文献阅读&#xff08;50&#xff09;—— Transformer 用于肺癌诊断预测先验知识/知识拓展文章结构背景文章方法1. 文章核心网络结构2. Time Encoding ViT &#xff08;TeViT&#xff09;3. Tim…

力扣刷题2023-05-04-1——题目:2614. 对角线上的质数

题目&#xff1a; 给你一个下标从 0 开始的二维整数数组 nums 。 返回位于 nums 至少一条 对角线 上的最大 质数 。如果任一对角线上均不存在质数&#xff0c;返回 0 。 注意&#xff1a; 如果某个整数大于 1 &#xff0c;且不存在除 1 和自身之外的正整数因子&#xff0c;…

Leetcode——66. 加一

&#x1f4af;&#x1f4af;欢迎来到的热爱编程的小K的Leetcode的刷题专栏 文章目录 1、题目2、暴力模拟(自己的第一想法)3、官方题解 1、题目 给定一个由 整数 组成的 非空 数组所表示的非负整数&#xff0c;在该数的基础上加一。最高位数字存放在数组的首位&#xff0c; 数组…

不同主题增删改查系统【控制台+MySQL】(Java课设)

有很多顾客都是只要实现各种各样的增删改查系统即可&#xff0c;只是主题和数据库表不一样&#xff0c;功能都是增删改查这四个功能&#xff0c;做出来的效果和下面的截图是一样的&#xff0c;后续这样的增删改查系统的运行效果请参考下面的截图&#xff0c;我就不一一演示了&a…

MATLAB实现工业PCB电路板缺陷识别和检测

PCB&#xff08;PrintedCircuitBoard印刷电路板&#xff09;是电子产品中众多电子元器件的承载体&#xff0c;它为各电子元器件的秩序连接提供了可能&#xff0c;PCB已成为现代电子产品的核心部分。随着现代电子工业迅猛发展&#xff0c;电子技术不断革新&#xff0c;PCB密集度…

【Git】‘git‘ 不是内部或外部命令,也不是可运行的程序

一、问题 我想利用git clone命令从github上下载项目源代码&#xff0c;发现报错&#xff1a; git 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。我用cmd跑一下git命令&#xff0c;发现报错&#xff1a; 二、问题分析 这个错误提示表明您的系统中没有安装…

电脑视频删除了怎么恢复回来?很着急

案例分享&#xff1a;“电脑视频删除了怎么恢复回来&#xff1f;我是一名影楼的摄像师&#xff0c;我的主要工作就是拍摄婚礼视频&#xff0c;最近拍了一场婚礼视频&#xff0c;当时由于相机的内存不足&#xff0c;于是将宣传片等视频都导入进了电脑里面&#xff0c;清空摄像机…

《软件工程教程》(第2版) 主编:吴迪 马宏茹 丁万宁 第八章课后习题参考答案

第八章 面向对象技术与UML 课后习题参考答案 一、单项选择题 D &#xff08;2&#xff09;C &#xff08;3&#xff09;B &#xff08;4&#xff09;D &#xff08;5&#xff09;C &#xff08;6&#xff09;B &#xff08;7&#xff09;A &#xff08;8&#xff09;C&…

2023华中杯数学建模C题完整模型代码

已完成全部模型代码&#xff0c;文末获取。 摘要 随着工业化和城市化的快速发展&#xff0c;空气污染已经成为全球性的环境问题。细颗粒物&#xff08;PM2.5&#xff09;等污染物对人类健康、生态环境和社会经济造成了严重影响。本研究旨在深入探究影响PM2.5浓度的主要因素&a…

ESP32(二):GPIO

一.创建例程 打开命令面板&#xff1a;ctrlshiftp&#xff0c;输入&#xff1a;esp-idf:example&#xff1b;选择hello_world工程&#xff0c;点击 Create project using example hello_world&#xff0c;选择保存工程&#xff1b;工具使用代码&#xff1a; #include <stdi…

【图像分割】视觉大模型SEEM(Segment Everything Everywhere All at Once)原理解读

文章目录 摘要&#xff08;效果&#xff09;二、前言三、相关工作四、method4.1 多用途4.2 组合性4.3 交互式。4.4 语义感知 五、实验 论文地址&#xff1a;https://arxiv.org/abs/2304.06718 测试代码&#xff1a;https://github.com/UX-Decoder/Segment-Everything-Everywher…

【Python】【进阶篇】14、Django创建第一个项目

目录 Django创建第一个项目1. 第一个项目BookStore1) BookStore项目创建 2. Django项目配置文件1) manage.py文件2) __init__.py文件3) settings.py文件4) urls.py文件5) wsgi.py文件 Django创建第一个项目 在上一章中&#xff0c;我们完成了开发环境的搭建工作。 本章我们将学…

NLP实战:基于Pytorch的文本分类入门实战

目录 一、前期准备 1.环境准备 2.加载数据 二、代码实战 1.构建词典 2.生成数据批次和迭代器 3. 定义模型 4. 定义实例 5.定义训练函数与评估函数 6.拆分数据集并运行模型 三、使用测试数据集评估模型 四、总结 这是一个使用PyTorch实现的简单文本分类实战案例。在…

【Java】内部类Object类

目录 1.内部类 1.1实例内部类 1.2静态内部类 1.3局部内部类 1.4匿名内部类 2.Object类 2.1getClass方法 2.2equals方法 2.3hashcode方法 1.内部类 定义&#xff1a;一个类定义在另一个类或一个方法的内部&#xff0c;前者称为内部类&#xff0c;后者称为外部类。 分…
最新文章