Java多线程实现的四种方式

2023-11-08

Java多线程实现的方式有四种

1 继承Thread类,重写run方法

2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target

3.通过Callable和FutureTask创建线程

4.通过线程池创建线程

前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void,所以没有办法返回结果
后面两种可以归结成一类:有返回值,通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中

线程实现方式1:继承Thread类的线程实现方式如下:


1.继承Thread类,重写run方法
2.实现Runnable接口,重写run方法,实现Runnable接口的实现类的实例对象作为Thread构造函数的target
3.通过Callable和FutureTask创建线程(future.get()接口会阻塞);
4.通过线程池创建线程

前面两种可以归结为一类:无返回值,原因很简单,通过重写run方法,run方式的返回值是void,所以没有办法返回结果
后面两种可以归结成一类:有返回值,通过Callable接口,就要实现call方法,这个方法的返回值是Object,所以返回的结果可以放在Object对象中

方式1:继承Thread类的线程实现方式如下:
package org.example.myThread;

public class ThreadDemo01 extends Thread {
    public ThreadDemo01() {
        //编写子类的构造方法,可缺省
    }

    public void run() {
        //编写自己的线程代码
        for (int i = 0; i < 3; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public static void main(String[] args) {

        ThreadDemo01 thread01 = new ThreadDemo01();
        ThreadDemo01 thread02 = new ThreadDemo01();
        thread01.setName("自定义的线程1");
        thread01.start();
        thread02.setName("自定义的线程2");
        thread02.start();

        //main线程
        System.out.println(Thread.currentThread().toString());
    }

}

自定义的线程2 0
自定义的线程2 1
自定义的线程2 2
Thread[main,5,main]
自定义的线程1 0
自定义的线程1 1
自定义的线程1 2

线程实现方式2:通过实现Runnable接口,实现run方法,接口的实现类的实例作为Thread的target作为参数传入带参的Thread构造函数,通过调用start()方法启动线程

package org.example.myThread;

class MyThread implements Runnable {
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for (int i = 0; i < 2; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
        System.out.println(Thread.currentThread().getName() + "-->我是通过实现接口的线程实现方式!");
    }
}

public class ThreadDemo02 {
    public static void main(String[] args) {
        Thread t1 = new Thread(new MyThread());
        t1.start();
        //thread 2
        new Thread(new MyThread()).start();
        //main线程
        System.out.println(Thread.currentThread().toString());
    }
}
Thread-0 0
Thread-0 1
Thread-0-->我是通过实现接口的线程实现方式!
Thread[main,5,main]
Thread-1 0
Thread-1 1
Thread-1-->我是通过实现接口的线程实现方式!

线程实现方式3:通过Callable和FutureTask创建线程

a:创建Callable接口的实现类 ,并实现Call方法
b:创建Callable实现类的实现,使用FutureTask类包装Callable对象,该FutureTask对象封装了Callable对象的Call方法的返回值
c:使用FutureTask对象作为Thread对象的target创建并启动线程
d:调用FutureTask对象的get()来获取子线程执行结束的返回值

package org.example.myThread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

class Tickets<Object> implements Callable<Integer> {
    private int i;

    public Tickets(int i) {
        this.i = i;
    }

    public int myFun(int i) {
        return i * 10;
    }

    //重写call方法
    @Override
    public Integer call() throws Exception {
        // TODO Auto-generated method stub
        System.out.println(Thread.currentThread().getName() + "-->我是通过实现Callable接口通过FutureTask包装器来实现的线程");
        return myFun(i);
    }
}

public class ThreadDemo03 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // TODO Auto-generated method stub

        Callable<Integer> oneCallable = new Tickets<Object>(2);
        FutureTask<Integer> oneTask = new FutureTask<Integer>(oneCallable);
        Thread t = new Thread(oneTask);
        t.start();
        System.out.println(oneTask.get());

        Callable<Integer> callable = new Tickets<Object>(3);
        FutureTask<Integer> task = new FutureTask<Integer>(callable);
        Thread t1 = new Thread(task);
        t1.start();
        System.out.println(task.get());

        //main线程
        System.out.println(Thread.currentThread().toString());
    }
}


Thread-0-->我是通过实现Callable接口通过FutureTask包装器来实现的线程
20
Thread-1-->我是通过实现Callable接口通过FutureTask包装器来实现的线程
30
Thread[main,5,main]

ExecutorService、Callable都是属于Executor框架。返回结果的线程是在JDK1.5中引入的新特征,还有Future接口也是属于这个框架,有了这种特征得到返回值就很方便了。
通过分析可以知道,他同样也是实现了Callable接口,实现了Call方法,所以有返回值。这也就是正好符合了前面所说的两种分类

执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了。get方法是阻塞的,即:线程无返回结果,get方法会一直等待。
————————————————

线程实现方式4:通过线程池创建线程

创建线程池底层均会调用ThreadPoolExecutor构造函数

public ThreadPoolExecutor(int corePoolSize,
                      int maximumPoolSize,
                      long keepAliveTime,
                      TimeUnit unit,
                      BlockingQueue<Runnable> workQueue) {

    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
        Executors.defaultThreadFactory(), defaultHandler);

}

  • corePoolSize:核心线程最大数量,通俗点来讲就是,线程池中常驻线程的最大数量。线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程;如果超过corePoolSize,则新建的是非核心线程。
  • maximumPoolSize:线程池中运行最大线程数(包括核心线程和非核心线程)
  • keepAliveTime:线程池中空闲线程(仅适用于非核心线程)所能存活的最长时间。当需要执行的任务很多,线程池的线程数大于核心池的大小时,keepAliveTime才起作用。
  • unit:存活时间单位,与keepAliveTime搭配使用(TimeUnit.DAYS,TimeUnit.HOURS,TimeUnit.MINUTES,TimeUnit.MILLISECONDS,TimeUnit.MICRODECONDS)
  • workQueue:存放任务的阻塞队列(维护着等待执行的
  • Runnable对象。当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务)。
  • handler:线程池饱和策略

在这里插入图片描述
线程池处理新提交任务流程

  1. 判断线程池中核心线程数是否已达阀值corePoolSize,若否,则创建一个新核心线程执行任务
  2. 若核心线程数已达阀值corePoolSize,判断阻塞队列workQueue是否已满,若未满,则将新任务添加进阻塞队列
  3. 若已满,判断线程池中线程数是否达到阀值maximumPoolSize,若否,则新建一个非核心线程执行任务。若达到阀值,则执行线程池饱和策略

java创建线程池的四种方式:

newCachedThreadPool 创建一个可缓存的线程池,如果线程池长度超过处理需求,可灵活回收空闲线程,若无可回收,则新建线程

newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待

newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行

newSingleThreadExecutor 创建一个单线程化的线程池,它只会唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行
package org.example.myThread;

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

public class ThreadDemo05 {
    private static int POOL_NUM = 5;     //线程池数量

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for (int i = 0; i < POOL_NUM; i++) {
            RunnableThread thread = new RunnableThread();
            Thread.sleep(100);
            executorService.execute(thread);
        }
        //关闭线程池
        executorService.shutdown();
    }

}

class RunnableThread implements Runnable {
    @Override
    public void run() {
        System.out.println("通过线程池方式创建的线程:" + Thread.currentThread().getName() + " ");
    }
}

通过线程池方式创建的线程:pool-1-thread-1 
通过线程池方式创建的线程:pool-1-thread-2 
通过线程池方式创建的线程:pool-1-thread-3 
通过线程池方式创建的线程:pool-1-thread-1 
通过线程池方式创建的线程:pool-1-thread-2 

扩展

应用

1.Callable接口

Runnable接口的实现类还是Callable接口的实现类,都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor执行。ThreadPoolExecutor或ScheduledThreadPoolExecutor都实现了 ExcutorService接口, 而因此 Callable需要和Executor框架中的ExcutorService结合使用,我们先看看ExecutorService提供的方法:

<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);

第一个方法:submit提交一个实现Callable接口的任务,并且返回封装了异步计算结果的Future。
第二个方法:submit提交一个实现Runnable接口的任务,并且指定了在调用Future的get方法时返回的result对象。
第三个方法:submit提交一个实现Runnable接口的任务,并且返回封装了异步计算结果的Future。

因此我们只要创建好我们的线程对象(实现Callable接口或者Runnable接口),然后通过上面3个方法提交给线程池去执行即可。还有点要注意的是,除了我们自己实现Callable对象外,我们还可以使用工厂类Executors来把一个Runnable对象包装成Callable对象。Executors工厂类提供的方法如下:

public static Callable<Object> callable(Runnable task)
public static <T> Callable<T> callable(Runnable task, T result)

2.Future接口

Future接口是用来获取异步计算结果的,就是对具体的Runnable或者Callable对象任务执行的结果进行获取(get()),取消(cancel()),判断是否完成等操作。

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
V get() :获取异步执行的结果,如果没有结果可用,此方法会阻塞直到异步计算完成。
V get(Long timeout , TimeUnit unit) :获取异步执行结果,如果没有结果可用,此方法会阻塞,但是会有时间限制,如果阻塞时间超过设定的timeout时间,该方法将抛出异常。
boolean isDone() :如果任务执行结束,无论是正常结束或是中途取消还是发生异常,都返回true。
boolean isCanceller() :如果任务完成前被取消,则返回true。
boolean cancel(boolean mayInterruptRunning) :
如果任务还没开始,执行cancel(...)方法将返回false;如果任务已经启动,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果停止成功,返回true;当任务已经启动,执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时返回false;当任务已经完成,执行cancel(...)方法将返回false。mayInterruptRunning参数表示是否中断执行中的线程。

通过方法分析我们也知道实际上Future提供了3种功能:(1)能够中断执行中的任务(2)判断任务是否执行完成(3)获取任务执行完成后额结果。
我们必须明白Future只是一个接口,我们无法直接创建对象,因此就需要其实现类FutureTask登场啦。

3.FutureTask类

public class FutureTask<V> implements RunnableFuture<V> {}

FutureTask类实现了RunnableFuture接口,看一下RunnableFuture接口的实现:

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
  }

分析:FutureTask除了实现了Future接口外还实现了Runnable接口,因此FutureTask也可以直接提交给Executor执行。 当然也可以调用线程直接执行(FutureTask.run())。接下来我们根据FutureTask.run()的执行时机来分析其所处的3种状态:

  • (1)未启动,FutureTask.run()方法还没有被执行之前,FutureTask处于未启动状态,当创建一个FutureTask,而且没有执行FutureTask.run()方法前,这个FutureTask也处于未启动状态。
  • (2)已启动,FutureTask.run()被执行的过程中,FutureTask处于已启动状态。
  • (3)已完成,FutureTask.run()方法执行完正常结束,或者被取消或者抛出异常而结束,FutureTask都处于完成状态。

4.Callable/Future/FutureTask的使用

4.1 使用Callable+Future获取执行结果
public class CallableDemo implements Callable<Integer> {
	
	private int sum;
	@Override
	public Integer call() throws Exception {
		System.out.println("Callable子线程开始计算啦!");
		Thread.sleep(2000);
		
		for(int i=0 ;i<5000;i++){
			sum=sum+i;
		}
		System.out.println("Callable子线程计算结束!");
		return sum;
	}
}
------------------------------------------------------------------------------------
public class CallableTest {
	
	public static void main(String[] args) {
		//创建线程池
		ExecutorService es = Executors.newSingleThreadExecutor();
		//创建Callable对象任务
		CallableDemo calTask=new CallableDemo();
		//提交任务并获取执行结果
		Future<Integer> future =es.submit(calTask);
		//关闭线程池
		es.shutdown();
		try {
			Thread.sleep(2000);
		System.out.println("主线程在执行其他任务");
		
		if(future.get()!=null){
			//输出获取到的结果
			System.out.println("future.get()-->"+future.get()); //get会被阻塞
		}else{
			//输出获取到的结果
			System.out.println("future.get()未获取到结果");
		}
		
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("主线程在执行完成");
	}
}
------------------------------------------------------------------------------------------------------------------------
Callable子线程开始计算啦!
主线程在执行其他任务
Callable子线程计算结束!
future.get()-->12497500
主线程在执行完成

4.2 使用Callable+FutureTask获取执行结果
public class CallableTest {
	
	public static void main(String[] args) {
//		//创建线程池
//		ExecutorService es = Executors.newSingleThreadExecutor();
//		//创建Callable对象任务
//		CallableDemo calTask=new CallableDemo();
//		//提交任务并获取执行结果
//		Future<Integer> future =es.submit(calTask);
//		//关闭线程池
//		es.shutdown();
		
		//创建线程池
		ExecutorService es = Executors.newSingleThreadExecutor();
		//创建Callable对象任务
		CallableDemo calTask=new CallableDemo();
		//创建FutureTask
		FutureTask<Integer> futureTask=new FutureTask<>(calTask);
		//执行任务
		es.submit(futureTask);
		//关闭线程池
		es.shutdown();
		try {
			Thread.sleep(2000);
		System.out.println("主线程在执行其他任务");
		
		if(futureTask.get()!=null){
			//输出获取到的结果
			System.out.println("futureTask.get()-->"+futureTask.get());
		}else{
			//输出获取到的结果
			System.out.println("futureTask.get()未获取到结果");
		}
		
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("主线程在执行完成");
	}
}
--------------------------------------------------------------------------------------------------------------------------------------------
Callable子线程开始计算啦!
主线程在执行其他任务
Callable子线程计算结束!
futureTask.get()-->12497500
主线程在执行完成

但其实这两种方法最终是一样的:
第一种方式Callable+Future最终也是以Callable+FutureTask的形式实现的。
在第一种方式中调用了: Future future = executor.submit(task);
那就让我们看看executor.submit(task)的源码吧:

//java.util.concurrent.AbstractExecutorService类中
   /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);//可以看到源码中其实是在submit(Callable<T> task)内部创建了一个RunnableFuture<T>接口实现类
        execute(ftask);
        return ftask;
    }''
    
    而FutureTask又是RunnableFuture的实现类,那就再看看newTaskFor(Callable callable)里面干了什么:

 protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }
    ```
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java多线程实现的四种方式 的相关文章

  • 如何使用 Java 和 Selenium WebDriver 在 C 目录中创建文件夹并需要将屏幕截图保存在该目录中?

    目前正在与硒网络驱动程序和代码Java 我有一种情况 我需要在 C 目录中创建一个文件夹 并在该文件夹中创建我通过 selenium Web 驱动程序代码拍摄的屏幕截图 它需要存储在带有时间戳的文件夹中 如果我每天按计划运行脚本 所有屏幕截
  • Java中反射是如何实现的?

    Java 7 语言规范很早就指出 本规范没有详细描述反射 我只是想知道 反射在Java中是如何实现的 我不是问它是如何使用的 我知道可能没有我正在寻找的具体答案 但任何信息将不胜感激 我在 Stackoverflow 上发现了这个 关于 C
  • 如何在 Play java 中创建数据库线程池并使用该池进行数据库查询

    我目前正在使用 play java 并使用默认线程池进行数据库查询 但了解使用数据库线程池进行数据库查询可以使我的系统更加高效 目前我的代码是 import play libs Akka import scala concurrent Ex
  • Java JDBC:更改表

    我希望对此表进行以下修改 添加 状态列 varchar 20 日期列 时间戳 我不确定该怎么做 String createTable Create table aircraft aircraftNumber int airLineCompa
  • 如何找到给定字符串的最长重复子串

    我是java新手 我被分配寻找字符串的最长子字符串 我在网上研究 似乎解决这个问题的好方法是实现后缀树 请告诉我如何做到这一点或者您是否有任何其他解决方案 请记住 这应该是在 Java 知识水平较低的情况下完成的 提前致谢 附 测试仪字符串
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • Final字段的线程安全

    假设我有一个 JavaBeanUser这是从另一个线程更新的 如下所示 public class A private final User user public A User user this user user public void
  • 无法展开 RemoteViews - 错误通知

    最近 我收到越来越多的用户收到 RemoteServiceException 错误的报告 我每次给出的堆栈跟踪如下 android app RemoteServiceException Bad notification posted fro
  • Liferay ClassNotFoundException:DLFileEntryImpl

    在我的 6 1 0 Portal 实例上 带有使用 ServiceBuilder 和 DL Api 的 6 1 0 SDK Portlet 这一行 DynamicQuery query DynamicQueryFactoryUtil for
  • 操作错误不会显示在 JSP 上

    我尝试在 Action 类中添加操作错误并将其打印在 JSP 页面上 当发生异常时 它将进入 catch 块并在控制台中打印 插入异常时出错 请联系管理员 在 catch 块中 我添加了它addActionError 我尝试在jsp页面中打
  • 我可以使用 HSQLDB 进行 junit 测试克隆 mySQL 数据库吗

    我正在开发一个 spring webflow 项目 我想我可以使用 HSQLDB 而不是 mysql 进行 junit 测试吗 如何将我的 mysql 数据库克隆到 HSQLDB 如果您使用 spring 3 1 或更高版本 您可以使用 s
  • 路径中 File.separator 和斜杠之间的区别

    使用有什么区别File separator和一个正常的 在 Java 路径字符串中 与双反斜杠相反 平台独立性似乎不是原因 因为两个版本都可以在 Windows 和 Unix 下运行 public class SlashTest Test
  • 十进制到八进制的转换[重复]

    这个问题在这里已经有答案了 可能的重复 十进制转换错误 https stackoverflow com questions 13142977 decimal conversion error 我正在为一个类编写一个程序 并且在计算如何将八进
  • 如何为俚语和表情符号构建正则表达式 (regex)

    我需要构建一个正则表达式来匹配俚语 即 lol lmao imo 等 和表情符号 即 P 等 我按照以下示例进行操作http www coderanch com t 497238 java java Regular Expression D
  • AWS 无法从 START_OBJECT 中反序列化 java.lang.String 实例

    我创建了一个 Lambda 函数 我想在 API 网关的帮助下通过 URL 访问它 我已经把一切都设置好了 我还创建了一个application jsonAPI Gateway 中的正文映射模板如下所示 input input params
  • Java执行器服务线程池[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 如果我使用 Executor 框架在
  • Google App Engine 如何预编译 Java?

    App Engine 对应用程序的 Java 字节码使用 预编译 过程 以增强应用程序在 Java 运行时环境中的性能 预编译代码的功能与原始字节码相同 有没有详细的信息这是做什么的 我在一个中找到了这个谷歌群组消息 http groups
  • Java列表的线程安全

    我有一个列表 它将在线程安全上下文或非线程安全上下文中使用 究竟会是哪一个 无法提前确定 在这种特殊情况下 每当列表进入非线程安全上下文时 我都会使用它来包装它 Collections synchronizedList 但如果不进入非线程安
  • 有没有办法为Java的字符集名称添加别名

    我收到一个异常 埋藏在第 3 方库中 消息如下 java io UnsupportedEncodingException BIG 5 我认为发生这种情况是因为 Java 没有定义这个名称java nio charset Charset Ch
  • 使用 JMF 创建 RTP 流时出现问题

    我正处于一个项目的早期阶段 需要使用 RTP 广播DataStream创建自MediaLocation 我正在遵循一些示例代码 该代码目前在rptManager initalize localAddress 出现错误 无法打开本地数据端口

随机推荐

  • windows文件夹挂载至Linux中

    背景 我们准备的安装包是需要在linux上使用docker compose进行部署 其中一个服务依赖GPU进行计算 需要能够使用到GPU 然而客户提供的是Windows服务器 且不能重装系统 并且最最最重要的是 NVIDIA的卡无法通过Hy
  • 解决ECharts关系点击图例节点偏移问题

    首先说问题原因 如果在没有设置x和y的坐标会出现这个问题 因为ECharts会开启自动布局算法所以在点击图例之后又将对应的图例进行的算法布局 所以才会导致数据偏移 解决办法 1 设置layout为none 禁止开启算法布局 layout n
  • 重排链表小结

    重排链表小结 又发现一道好玩的题目 顺带来复习一下之前学过的知识吧 Leetcode题目 143 重排链表 给定一个单链表 L 的头节点 head 单链表 L 表示为 L0 L1 Ln 1 Ln 请将其重新排列后变为 L0 Ln L1 Ln
  • Contruct 2制作的HTML5游戏的简单介绍

    游戏背景 在主宰大陆上生活着这样一群人 他们生来掌握着强大的魔法力量 然而自然界从来不允许什么生物可以一家独大 所以与之对应一群强大的魔法生物诞生了 一场人与兽的较量就此展开 伊琳娜是喀布尔山脉的守护者 负责保护阿帕丝女神的雕像 这天阳光正
  • windows配置了path系统环境变量但是不生效

    在配置path环境变量时发现配置的环境变量压根没有效果 但是环境变量内容也没写错 那多半是这个原因 正确的 C Program Files x86 NVIDIA Corporation PhysX Common SystemRoot sys
  • zabbix通过IPMI监控硬件环境(温度和风扇)

    IPMI Intelligent PlatformManagement Interface 即智能平台管理接口是使硬件管理具备 智能化 的新一代通用接口标准 用户可以利用 IPMI 监视服务器的物理特征 如温度 电压 电扇工作状态 电源供应
  • Windows通过计划任务定时执行bat文件

    首先打开Windows系统的 开始 菜单 从中依次点选 程序 附件 系统工具 任务计划程序 命令 点击 创建任务 后如图所示 填写好相应的名称和勾选好必要的条件 选择 触发器 选项 点击 新建 创建任务执行时间 重复任务间隔 这个选择后 后
  • 常见登录鉴权方案

    编者注 今天我们分享的是卢士杰同学整理的网站常用鉴权方案的实现原理与实现以及他们的适用场景 帮助大家在业务中做合适的选择 背景 说起鉴权大家应该都很熟悉 不过作为前端开发来讲 鉴权的流程大头都在后端小哥那边 本文的目的就是为了让大家了解一下
  • 360的服务器在哪个文件夹,如何卸载服务器上顽固的360

    前几天接触到一台戴尔R410的服务器 已经尘封两年 忘记密码无法进入系统 系统是经典的windows server 2003 于是直接用量化好暗组优盘系统的U盘启动 在这里要注意下 服务器的按del是没用的 需要按F12 进入后 选择u盘启
  • 服务器装win10稳定吗,win11发布了,那么电脑安装win11稳定吗?win11稳定性介绍

    近期新的win11系统出去后 绝大多数用户都很希望 但也是有许多平稳用户由于还不知道这一系统如何 因此迟疑需不需要升级 实际上 现在是预览版系统镜像系统 或多或少会出现一点bug 但整体而言或是相对稳定 下面大家一起来看看win11平稳吗的
  • 代码随想录训练营第五十九天

    1 下一个更大元素II 题503 循环数组有两种方法 一是用同一个数组拼接成两个数组 实现假循环 二是遍历两遍 用求余的方法 求余的方法更简便 class Solution public vector
  • java 变量的生命周期

    这个要从作用域开始说起 像局部变量的作用域就是他的生命周期 比如if for switch等等这些 出了这个结构就销毁了 方法里的局部变量 在方法调用完就销毁 如果是类的成员变量 在类的相应的对象销毁的时候销毁 上面说的是普通变量 如果是静
  • 卷积处理过程模拟:用Python实现OpenCV函数filter2D等效的卷积功能

    一 引言 在 OpenCV Python 图像平滑处理 卷积函数filter2D详解及均值滤波案例 介绍了filter2D相关的功能及使用 下面老猿用Python numpy矩阵运算以及OpenCV Python的图像基础操作模拟实现一个卷
  • mybatis之执行sql语句

    写在前面 通过这篇文章的分析 已经生成了可以执行的sql语句了 本文来分析SQL语句具体的执行过程 想要系统学习的 可以参考这篇文章 重要 入口 当我们执行一次数据查询的时候 mybatis会通过org apache ibatis exec
  • 4路组相连cache设计_cache基本原理

    为什么要了解cache 在学习linux kernel的过程 经常会cache的概念 从软件层面的page buffer cache 再到硬件层面中CPU的L1 L2 L3 cache TLB 磁盘内部的硬件cache 以及编程时的cach
  • 集合框架--双向链表的模拟实现

    Java中的鏈表 分為三種 1 單向鏈表 由一個節點元素 可以找到相鄰的下一個節點元素 2 雙向鏈表 由一個節點元素 可以找到其相鄰的前 后節點元素 3 循環鏈表 由一個節點元素 可以找到其相鄰的前 后節點元素 由最后一個節點元素可以找到第
  • notepad使用回车与换行

    转载于 http www pythontab com html 2017 linuxkaiyuan 0115 1116 html 一 回车与换行定义 回车 r 本义是光标重新回到本行开头 r的英文return 换行 n 本义是光标往下一行
  • 浅谈Spring中的@Controller注解

    Spring 的 Controller 是单例还是多例 怎么保证并发的安全 controller默认是单例的 不要使用非静态的成员变量 否则会发生数据逻辑混乱 正因为单例所以不是线程安全的 Controller public class S
  • buuctf-misc-小明的保险箱

    小明的保险箱 题目提示四位纯数字密码 但是附件下载下来是jpg文件 猜测是压缩包文件 winhex查看时没有找到什么信息 但是看到了存在txt文件 binwalk一下 把文件放入共享文件夹 上一个博客有提及 binwalk 存在压缩文件 f
  • Java多线程实现的四种方式

    Java多线程实现的方式有四种 1 继承Thread类 重写run方法 2 实现Runnable接口 重写run方法 实现Runnable接口的实现类的实例对象作为Thread构造函数的target 3 通过Callable和FutureT