当前位置: 首页 > article >正文

【多线程基础】线程状态 同步 协作 线程池 Lambda表达式

一、基本概念进程 Process进程就是执行程序的一次执行过程它是一个动态的概念是系统资源分配的单位通常在一个进程中可以包含若干个线程当然一个进程中至少有一个线程不然没有存在的意义线程是CPU调度和执行的单位线程 Thread线程就是独立的执行路径在程序运行时即使没有自己创建线程后台也会有多个线程比如主线程GC线程main()称之为主线程为系统的入口用于执行整个程序在一个进程中如果开辟了多个线程线程的运行是由调度器安排调度的调度器是与操作系统紧密相关的先后顺序是不能人为干预的对同一份资源操作时会存在资源抢夺的问题,需要加入并发控制线程会带来额外的开销如CPU调度时间并发控制开销每个线程在自己的工作内存交互内存控制不当会造成数据不一致多线程二、线程创建1、继承 Thread 类Thread 类实现了 Runnable 接口1.1、实现步骤继承Thread类重写run方法创建实例调用start方法public class ThreadTest extends Thread{ Override public void run() { for (int i 0; i 200; i) { System.out.println(我的线程i); } } public static void main(String[] args) { ThreadTest threadTest new ThreadTest(); threadTest.start(); //threadTest.run(); for (int i 0; i 2000; i) { System.out.println(主线程i); } } }1.2、start 和 run 方法的区别?start通过调用Thread类的 start()方法来启动一个线程这时此线程处于就绪(可运行)状态并没有运行一旦得到cpu时间片就开始执行run()方法runrun()方法 称为线程体。只是类的一个普通方法而已。如果直接调用Run方法程序中依然只有主线程这一个线程其程序执行路径还是只有一条还是要顺序执行还是要等待run方法体执行完毕后才可继续执行下面的代码这样就没有达到写线程的目的。1.3、多线程下载图片案例package com.ajun; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; /** * author ajun * Date 2021/6/27 * version 1.0 */ public class WebDown extends Thread{ private String url; private String file; public WebDown(String url,String file){ this.url url; this.file file; } Override public void run() { WebDownLoader webDownLoader new WebDownLoader(); webDownLoader.downLoader(url,file); System.out.println(下载了图片file); } public static void main(String[] args) { WebDown t1 new WebDown(https://img2020.cnblogs.com/blog/2429409/202106/2429409-20210623132753966-565643795.jpg, 1.jpg); WebDown t2 new WebDown(https://img2020.cnblogs.com/blog/2429409/202106/2429409-20210618095622043-1605637963.jpg, 2.jpg); WebDown t3 new WebDown(https://img2020.cnblogs.com/blog/2429409/202106/2429409-20210614212002983-1003721756.jpg, 3.jpg); t1.start(); t2.start(); t3.start(); } } //下载器 class WebDownLoader{ //下载方法 public void downLoader(String url,String file){ try { FileUtils.copyURLToFile(new URL(url),new File(file)); } catch (IOException e) { e.printStackTrace(); } } }2、实现 Runnable 接口 (推荐)2.1、实现步骤实现Runnable接口Runnable 接口只有run()方法实现run方法创建Thread时作为参数传入,调用start方法public class RunnableTest implements Runnable{ Override public void run() { for (int i 0; i 200; i) { System.out.println(我的线程i); } } public static void main(String[] args) { //创建一个实现 Runnable 接口的类 RunnableTest runnableTest new RunnableTest(); //创建线程把实现Runnable接口的类对象作为参数传入 new Thread(runnableTest).start(); for (int i 0; i 2000; i) { System.out.println(主线程i); } } }2.2、龟兔赛跑public class Race implements Runnable { //胜利者 private static String winner ; //距离 private int m 1_0000_0000; Override public void run() { for (int i 1; i m1; i) { //选手 String player Thread.currentThread().getName(); //兔子每10米就休息 if (player.equals(兔子) i % 10 0) { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } //判断比赛是否结束 if (gameOver(i)) { System.out.println(player --- 跑了 i 米); break; } } } //判断比赛是否结束 private boolean gameOver(int m1) { if (winner ! ) {//已经有胜利者 return true; } else {//没有胜利者 if (m1 m) {//已到达终点 winner Thread.currentThread().getName(); System.out.println(winner 赢了); return true; } } return false; } public static void main(String[] args) { Race race new Race(); new Thread(race, 乌龟).start(); new Thread(race, 兔子).start(); } }3、实现 Callable 接口 (了解)3.1、步骤3.2、改造多线程下载图片案例public class WebDownCallable implements CallableBoolean { private String url; private String file; public WebDownCallable(String url, String file) { this.url url; this.file file; } Override public Boolean call() throws Exception { WebDownLoader1 webDownLoader new WebDownLoader1(); webDownLoader.downLoader(url, file); System.out.println(下载了图片 file); return true; } public static void main(String[] args) throws ExecutionException, InterruptedException { WebDownCallable t1 new WebDownCallable(https://img2020.cnblogs.com/blog/2429409/202106/2429409-20210623132753966-565643795.jpg, 1.jpg); WebDownCallable t2 new WebDownCallable(https://img2020.cnblogs.com/blog/2429409/202106/2429409-20210618095622043-1605637963.jpg, 2.jpg); WebDownCallable t3 new WebDownCallable(https://img2020.cnblogs.com/blog/2429409/202106/2429409-20210614212002983-1003721756.jpg, 3.jpg); //创建执行服务创建线程池 ExecutorService service Executors.newFixedThreadPool(3); //提交执行 FutureBoolean s1 service.submit(t1); FutureBoolean s2 service.submit(t2); FutureBoolean s3 service.submit(t3); //得到返回值 Boolean re1 s1.get(); Boolean re2 s2.get(); Boolean re3 s3.get(); System.out.println(re1); System.out.println(re2); System.out.println(re3); //关闭服务 service.shutdownNow(); } } //下载器 class WebDownLoader1 { //下载方法 public void downLoader(String url, String file) { try { FileUtils.copyURLToFile(new URL(url), new File(file)); } catch (IOException e) { e.printStackTrace(); } } }三、Lambda表达式 (箭头函数)1、介绍λ 希腊字母表中排序第十一位的字母英语名称为 Lambda (兰布达)Lambda表达式 就是 箭头函数。是JDK1.8的一种新特性(语法糖)避免匿名内部类定义过多可以让代码看起来很简洁去掉了一堆没有意义的代码留下核心的逻辑其实质属于函数式编程的概念(params)- expression[表达式] (params) - statement[语句] (params) - {statements}2、函数式接口理解Functional interface(函数式接口)是学习java8 lamda表达式的关键所在函数式接口的定义任何接口如果只包含一个方法那么它就是一个函数式接口public interface Runnable{ public abstract void run(); }对于函数式接口我们可以通过lamda表达式来创建该接口的对象3、示例3.1、定义接口//接口 //只有一个方法 interface ILike{ void lambda(); //带参数 //void lambda(int n); }3.2、传统实现类public class LambdaTest { public static void main(String[] args) { ILike1 iLike1 new ILike1(); iLike1.lambda();//lambda1 } } //传统实现类 class ILike1 implements ILike{ Override public void lambda() { System.out.println(lambda1); } //带参数 //Override //public void lambda(int a) { // System.out.println(lambda1---a); //} }3.3、静态内部类public class LambdaTest { //静态内部类 static class ILike2 implements ILike{ Override public void lambda() { System.out.println(lambda2); } } public static void main(String[] args) { ILike2 iLike2 new ILike2(); iLike2.lambda(3); //lambda2 } }3.4、局部内部类public class LambdaTest { public static void main(String[] args) { //局部内部类 class ILike3 implements ILike{ Override public void lambda() { System.out.println(lambda3); } } ILike3 iLike3 new ILike3(); iLike3.lambda(); //lambda3 } }3.5、匿名内部类public class LambdaTest { public static void main(String[] args) { //匿名内部类 //new 接口 { 实现方法 } ILike iLike4 new ILike() { Override public void lambda() { System.out.println(lambda4); } }; iLike4.lambda(); //lambda4 } }3.6、Lambda表达式完整写法public class LambdaTest { public static void main(String[] args) { //Lambda表达式 ILike i5 () - { System.out.println(lambda5); }; i5.lambda(); //lambda5 } }简写 (省花括号)方法中只有一条执行语句时省略花括号public class LambdaTest { public static void main(String[] args) { //方法中只有一条执行语句时 //花括号可以省略 ILike i5 () - System.out.println(lambda6); i5.lambda(); //lambda6 } }简写(只有一个参数时省略小括号)public class LambdaTest { public static void main(String[] args) { //只有一个参数时省略小括号 ILike i5 a - System.out.println(lambda7---a); i5.lambda(5); //lambda7---5 } }四、线程状态1、状态statepublic enum State { NEW,//新线程未启动 RUNNABLE,//可运行(包含就绪状态 和 运行状态) BLOCKED,//阻塞 WAITING,//等待 TIMED_WAITING,//超时等待 TERMINATED;//中止 }2、线程方法getName()setName()2.1、线程停止2.2、线程休眠 sleep()sleep(毫秒数)指定当前线程停止的时间sleep()存在异常InteruptedExceptionsleep()时间到达后线程进入就绪状态sleep()可以模拟网络延时、倒计时等每一个对象都有一个锁sleep不会释放锁2.3、线程礼让 yield()礼让线程让当前正在执行的线程暂停但不阻塞将线程从运行状态转为就绪状态让CPU重新调度礼让不一定成功看CPU心情2.4、线程强制执行 join()Join合并线程待此线程执行完成后再执行其他线程其他线程阻塞可以想象成插队public class ThreadJoinTest implements Runnable{ Override public void run() { for (int i 0; i 10; i) { System.out.println(线程VIP来了i); } } public static void main(String[] args) throws InterruptedException { ThreadJoinTest joinTest new ThreadJoinTest(); Thread thread new Thread(joinTest); thread.start(); for (int i 0; i 100; i) { if(i30){ thread.join(); } System.out.println(maini); } } }2.5、线程优先级java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程线程调度器按照优先级决定该调度哪个线程来执行线程的优先级用数字来表示范围从1~10Thread.MIN_PRIORITY 1Thread.MAX_PRIORITY 10Thread.NORM_PRIORITY 5使用getPriority()和setPriority()来获取或改变优先级2.6、守护线程setDeamon()setDeamon(true)线程分为用户线程和守护线程虚拟机必须确保用户线程执行完毕虚拟机不用等待守护线程执行完毕如后台记录操作日志监控内存垃圾回收五、线程同步1、介绍处理多线程问题时多个线程访问同一个对象并且某些线程还想修改这个对象这时候我们就需要线程同步线程同步其实是一种等待机制多个需要同时访问此对象的线程进入这个对象的等待池形成队列等待前面的线程使用完毕下一个线程在使用由于同一进程的多个线程共享同一块存储空间在带来方便的同时也带来了访问的冲突问题为了保证数据在方法中被访问时的正确性在访问时加入锁机制syncronized当一个线程获得对象的排他锁独占资源其他线程必须等待使用后释放锁即可,存在一下问题一个线程持有锁会导致其他所有需要此锁的进程挂起在多线程竞争的情况下加锁释放锁会导致比较多的上下文切换和调度延时引起性能问题如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置引起性能问题2、同步方法 和 同步块同步块synchronized(obj){ }obj称之为同步监视器obj可以是任何对象但是推荐使用共享资源作为同步监视器同步方法在方法上添加synchronized关键字锁的是对象本身同步方法中无需指定同步监视器因为同步方法中的同步监视器就是this就是这个对象本身或者是class同步监视器的执行过程第一个线程访问锁定同步监视器执行其中的代码第二个线程访问发现同步监视器被锁定无法访问就等待第一个线程访问完毕解锁同步监视器第二个线程访问发现同步监视器没有锁然后锁定并访问3、三大不安全案例3.1、买票public class BuyTicketTest { public static void main(String[] args) { BuyTicket buyTicket new BuyTicket(); new Thread(buyTicket,小张).start(); new Thread(buyTicket,小王).start(); new Thread(buyTicket,小李).start(); } } class BuyTicket implements Runnable{ private int ticketNum 10; boolean flag true; Override public void run() { while (flag){ buy(); } } //同步方法 private synchronized void buy(){ if(ticketNum 1){ flag false; return; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() 拿到了 ticketNum--); } }解决办法把买票方法 buy 同步3.2、取钱public class BankTest { public static void main(String[] args) { Account account new Account(100, 结婚基金); TakeMoney myWife new TakeMoney(account, 80); TakeMoney my new TakeMoney(account, 50); new Thread(myWife,我的妻子).start(); new Thread(my,我).start(); } } //账户 class Account { private int money; private String name; public Account(int money, String name) { this.money money; this.name name; } public int getMoney() { return money; } public void setMoney(int money) { this.money money; } public String getName() { return name; } public void setName(String name) { this.name name; } } //取钱 class TakeMoney implements Runnable { Account account;//账户 int takeNum;//存走的钱 int nowNum;//手里的钱 public TakeMoney(Account account, int takeNum) { this.account account; this.takeNum takeNum; } Override public void run() { //同步块把账户 account 同步 synchronized (account){ String threadName Thread.currentThread().getName(); //判断是否有钱 if (account.getMoney() - takeNum 1) { System.out.println(threadName 钱不够了); return; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } //卡内余额 account.setMoney(account.getMoney() - takeNum); //手里的钱 nowNum nowNum takeNum; System.out.println(account.getName() 余额为account.getMoney()); System.out.println(threadName 手里的钱为nowNum); } } }解决办法同步块把账户 account 同步3.3、线程不安全集合public class CollectionTest { public static void main(String[] args) throws InterruptedException { ListString list new ArrayList(); for (int i 0; i 10000; i) { new Thread(()-{ //同步块对集合 list 同步 synchronized (list){ list.add(Thread.currentThread().getName()); } }).start(); } Thread.sleep(3000); System.out.println(list.size()); } }解决办法同步块对集合 list 同步4、死锁4.1、死锁分析多个线程各自占有一些共享资源并且互相等待其他线程占有的资源释放才能运行而导致两个或者多个线程都在等待对方释放资源都停止执行的情形某一个同步块同时拥有两个以上的对象锁时就可能发生死锁现象4.2、死锁产生的必要条件互斥条件 一个资源每次只能被一个线程使用请求保持条件 一个线程因请求资源而阻塞时对以获得的资源保持不放不剥夺条件线程已获得的资源在未使用完之前不能强行剥夺循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系4.3、死锁避免方法5、释放锁Java多线程运行环境中在哪些情况下会使对象锁释放由于等待一个锁的线程只有在获得这把锁之后才能恢复运行所以让持有锁的线程在不再需要锁的时候及时释放锁是很重要的。在以下情况下持有锁的线程会释放锁执行完同步代码块就会释放锁。(synchronized)在执行同步代码块的过程中遇到异常而导致线程终止锁也会被释放。(exception)在执行同步代码块的过程中执行了锁所属对象的wait()方法这个线程会释放锁进入对象的等待池。(wait)除了以上情况以外只要持有锁的线程还没有执行完同步代码块就不会释放锁在下面情况下线程是不会释放锁的执行同步代码块的过程中执行了Thread.sleep()方法当前线程放弃CPU开始睡眠进入堵塞状态在睡眠中不会释放锁在执行同步代码块的过程中执行了Thread.yield()方法当前线程放弃CPU回到就绪状态但不会释放锁方法是否释放锁wait()释放sleep()不释放yield()不释放6、Lock锁从JDK1.5开java提供了更为强大的线程同步机制——通过显式定义同步锁对象来实现同步同步锁使用lock对象来充当java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问每次只能有一个线程对Lock对象加锁线程开始访问共享资源之前应先获得Lock对象ReentrantLock类实现了Lock它拥有与synchronized相同的并发性和内存语义在实现线程安全的控制中比较常用的是ReentrantLock可以显示加锁,释放锁class BuyTicket implements Runnable{ //定义锁 private ReentrantLock lock new ReentrantLock(); private int ticketNum 10; boolean flag true; Override public void run() { while (flag){ buy(); } } //synchronized private void buy(){ lock.lock();//加锁 try{ //业务代码 if(ticketNum 1){ flag false; return; } try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() 拿到了 ticketNum--); }finally { lock.unlock();//解锁 } } }7、Lock 与 synchronizedLock是显式锁(手动开启和关闭别忘记关闭锁) synchronized是隐式锁出了作用域自动释放Lock只有代码块锁synchronized有代码块锁和方法锁使用lock锁JVM将花费较少的时间来调度线程性能更好并且具有更好的扩展性(提供更多的子类)优先使用顺序Lock 同步代码块 同步方法比较Locksynchronized类型java接口内置关键字开启释放显式锁手动 开启 和 关闭隐式锁出了作用域自动释放代码锁支持支持方法锁不支持支持锁状态可以判断是否获取到了锁无法判断获取锁的状态线程阻塞Lock锁就不一定会等待下去线程1(获得锁阻塞)线程2(等待)可重入性可重入的可以判断锁可重入锁不可以中断的公平性默认非公平的(可设置)非公平的性能性能更好JVM将花费较少的时间来调度性能一般JVM将花费较多的时间来调度管理扩展性有更好的扩展性(提供更多的子类)不支持适用场景适合锁大量的同步代码适合锁少量的代码同步问题六、线程协作1、生产者和消费者问题假设仓库中只能存放一件产品生产者将生产出来的产品放入仓库消费者将仓库产品取走消费如果仓库中没有产品则生产者将产品放入仓库否则停止生产并等待直到仓库中的产品被消费者取走为止如果仓库中放有产品则消费者可以将产品取走消费否则停止消费并等待直到仓库中再次放入产品为止这是一个线程同步问题生产者和消费者共享一个资源并且生产者和消费者之间相互依赖互为条件对于生产者没有生产产品之前要通知消费者等待生产了产品之后又要马上通知消费者消费对于消费者在消费之后要通知生产者已经结束消费需要生产新的产品以供消费在生产者、消费者问题上仅有 synchronized 是不够的synchronized 可阻止并发更新同一个共享资源实现了同步synchronized 不能用来实现不同线程之间消息传递(通信)2、Java 中解决线程间通信的方法wait() 与 sleep() 区别wait 在等待时会释放锁sleep 在等待时不会释放锁(抱着锁睡觉)3、解决方案3.1、管程法生产者负责生产数据的模块(可能是方法对象线程数组)消费者:负责处理数据的模块(可能是方法对象线程数组)缓冲区消费者不能直接使用生产者的数据他们之间有个缓冲区生产者将生产好的数据放入缓冲区消费者从缓冲区拿出数据package com.ajun; import java.util.concurrent.locks.ReentrantLock; /** * author ajun * Date 2021/6/28 * version 1.0 * 生产者、消费者问题 * 管程法 */ public class PCTest { public static void main(String[] args) { //定义仓库 Repository repository new Repository(); //生产者 Provider provider new Provider(repository); //消费者 Consumer consumer new Consumer(repository); new Thread(provider).start(); new Thread(consumer).start(); } } //产品 class Product { private int id; public int getId() { return id; } public void setId(int id) { this.id id; } public Product(int id) { this.id id; } } //生产者 class Provider implements Runnable { //有仓库属性 private Repository repository new Repository(); //构造器 public Provider(Repository repository) { this.repository repository; } Override public void run() { //循环生产100件产品 for (int i 1; i 101; i) { System.out.println(生产了第 i 件产品); //存入仓库 repository.push(new Product(i)); } } } //消费者 class Consumer implements Runnable { //有仓库属性 private Repository repository new Repository(); //构造器 public Consumer(Repository repository) { this.repository repository; } Override public void run() { //循环消费100件产品 for (int i 1; i 101; i) { //从仓库取出 Product product repository.out(); System.out.println(消费了第 product.getId() 件产品); } } } //仓库(缓存区) class Repository { //存放产品的数组 Product[] products new Product[10]; int count 0;//计数器 //生产者放入产品 //放产品时需要线程同步 public synchronized void push(Product product) { //判断仓库是否满了 if(count products.length){//满了 try { this.wait();//等待 } catch (InterruptedException e) { e.printStackTrace(); } } //仓库没有满 products[count] product;//把产品放入仓库 count;//计器数加1 //通知消费者可以消费了 this.notifyAll(); } //消费者取产品 //取产品时需要线程同步 public synchronized Product out() { //Product product null; //判断仓库中是否有产品 if(count 0){//没有产品 try { this.wait();//等待 } catch (InterruptedException e) { e.printStackTrace(); } }/*else{//有产品 count--;//计数器减1 product products[count];//取出产品 }*/ count--;//计数器减1 Product product products[count];//取出产品 this.notifyAll(); return product; } }在有 wait 和 notityAll 的同步时不能用 ReentrantLockwait 、notity 方法只能在 同步方法 或 同步代码块 中使用否则会抛出 IllegalMonitorStateException 异常3.2、信号灯法package com.ajun; /** * author ajun * Date 2021/6/28 * version 1.0 * 生产者、消费者问题 * 信号灯法 */ public class PCTest1 { public static void main(String[] args) { TV tv new TV(); Player player new Player(tv); Watcher watcher new Watcher(tv); new Thread(player).start(); new Thread(watcher).start(); } } //生产者演员 class Player implements Runnable { private TV tv; public Player(TV tv) { this.tv tv; } Override public void run() { for (int i 0; i 5; i) { tv.play(第 (i 1) 个节目); } } } //消费者观众 class Watcher implements Runnable { private TV tv; public Watcher(TV tv) { this.tv tv; } Override public void run() { for (int i 0; i 5; i) { tv.watch(); } } } //产品节目 class TV { //具体节目 String voice; //控制开关 //节目未上映演员生产观众等待false //节目已上映观众观看演员休息等待true boolean flag false;//未上映 //表演 public synchronized void play(String voice) { //如果已上映观众正在观看这里演员就可以等待休息 if (flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(演员制作完成上映了 voice); //展示节目 this.voice voice; //通知观众观看 this.notifyAll(); //更新控制开关 this.flag !this.flag; } //观看 public synchronized void watch() { //如果未上映演员正在制作观众休息等待 if (!flag) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(观众观看了 voice); //通知演员制作 this.notifyAll(); //更新控制开关 this.flag !this.flag; } }七、线程池1、介绍背景经常创建和销毁使用量特别大的资源比如并发情况下的线程对性能影响很大思路提前创建好多个线程放入线程池中使用时直接获取使用完毕放回池中可以避免频繁的创建销毁实现重复利用类似生活中的公共交通工具好处提高了响应速度(减少了创建新线程的时间)降低资源消耗(重复利用线程池中线程不需要每次都创建)便于线程管理(…)corePoolSize 核心池的大小maximumPoolSize最大线程数keepAliveTime 线程没有任务时最多保持多长时间后会终止2、使用线程池线程池工具类 Executors2.1、execute()没有返回值执行 Runnable 线程类package com.ajun; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * author ajun * Date 2021/6/28 * version 1.0 */ public class ThreadPoolTest { public static void main(String[] args) { //用线程池工厂类 Executors,创建线程池 ExecutorService service Executors.newFixedThreadPool(10); //执行线程 service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); service.execute(new MyThread()); //关闭连接 service.shutdown(); } } //实现Runnable接口的类 class MyThread implements Runnable{ Override public void run() { System.out.println(Thread.currentThread().getName()); } }2.2、submit()有返回值 Future执行 Callable 接口的类package com.ajun; import java.util.concurrent.*; /** * author ajun * Date 2021/6/28 * version 1.0 */ public class ThreadPoolTest1 { public static void main(String[] args) throws ExecutionException, InterruptedException { //用线程池工厂类 Executors,创建线程池 ExecutorService service Executors.newFixedThreadPool(10); //提交执行 FutureBoolean s1 service.submit(new MyThread1()); FutureBoolean s2 service.submit(new MyThread1()); FutureBoolean s3 service.submit(new MyThread1()); //得到返回值 Boolean rs1 s1.get(); Boolean rs2 s2.get(); Boolean rs3 s3.get(); //关闭连接 service.shutdown(); } } class MyThread1 implements CallableBoolean{ Override public Boolean call() throws Exception { System.out.println(Thread.currentThread().getName()); return true; } }

相关文章:

【多线程基础】线程状态 同步 协作 线程池 Lambda表达式

一、基本概念进程 Process进程就是执行程序的一次执行过程,它是一个动态的概念,是系统资源分配的单位通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义,线程是CPU调度和执行的单位…...

数据结构___线性表

2.1线性表的定义(逻辑结构):●定义: 具有相同数据类型的N(N>0)个数据元素的有限序列,其中N为表长,当N 0 时,线性表时一个空表.表示 L (a1,a2,...,ai, ai1, ..., an)●每个数据元素所占空间一样大.有限的序列. 注意 用数组实现线性表下标从0开始.●位序 :从1开始的,一个线…...

【Xilinx Vivado 时序分析/约束系列10】FPGA开发时序分析/约束-FPGA DDR-Direct接口的 input delay 约束优化方法

目录 DDR采样简述 第一种模型(不带PLL) 实际操作 总结约束 实际工程 顶层代码 时钟约束 input delay约束 查看时序报告 解决办法 添加原语 原语解释 查看时序报告 时序分析 总结 往期系列博客 DDR采样简述 在之前分析了SDR采样&#xff…...

SAP ML81N消息号SE729提示用户定制被错误的维护的解决方案

SAP PS模块日常解决方案 文章目录SAP PS模块日常解决方案前言在SAP使用过程中,服务类的采购订单在使用ML81N进行服务确认操作时,已经操作成功,但是系统会提示消息号SE729:提示用户定制被错误的维护。 注意:以下内容是基…...

构建画面记忆法

目录:一、十二地支记忆二、十天干记忆三、51位圆周率记忆文|随意的风:联锁拍照,产生一幅一幅的图片,将图片以故事摄影方式联系在一起。将右脑充分开发出来。一、十二地支记忆1、饺子,交子,夜半子时。半夜里…...

CorelDRAW_X6使用汇总

目录: 一、软件的下载、安装与注册 1、软件下载 2、软件注册 二、软件的使用 1、页面布局 2、坐标原点设置在图纸的中心 3、标注尺寸 4、颜色处理 5、合并对象为一个单元 6、导角 7、文字的添加与修改 8、图形绘制 9、对象的图层切换 10、图形去描边、…...

COMSOL多物理场/FDTD时域有限差分/ RSoft光电器件仿真设计“ 几十种案例解析,助您掌握光电器件仿真模拟

光电作为物理类专业课程中极为重要的一部分,其教学内容一直受到各个高校的重视。结合目前许多学生对实验开展的痛难点,将软件仿真引入实验当中,通过软件的可视化处理有效直观的展示光电仿真的流程,与实验数据结合,使得…...

【Verilog】布斯算法(Booth Algorithm)乘法器的 Verilog 实现

目录 布斯算法介绍 计算步骤 计算流程图 举个栗子 Verilog 实现 设计思想 Verilog 代码 TestBench 代码 仿真波形 布斯算法介绍 Booth 的算法检查有符号二的补码表示中 N位乘数 Y 的相邻位对,包括低于最低有效位 y−1 0 的隐式位。对于每个位 yi&#xf…...

【HDLBits 刷题 13】Buliding Larger Circuits

目录 写在前面 Buliding Larger Circuits count1k shiftcount fsm seq fsmshift fsm fancytimer fsm onehot 写在前面 以下的解题方法不一定为最佳解决方案,有更好的方法欢迎提出,共同学习,共同进步! Buliding Larger …...

无符号类型给有符号类型赋值符号位的问题

记一次bug问题分析问题 再写modbus通信协议解析的时候遇到一个问题,计算CRC的时候返回值是一个unsigned short,接受的时候我定义的结构体里的CRC是一个有符号 short,也是头一次遇到有无符号位的问题。下面我把具体代码贴出来。 if(pModbusWr…...

【HDLBits 刷题 9】Circuits(5)Finite State Manchines 1-9

目录 写在前面 Finite State Manchines Fsm1 Fsm1s Fsm2 Fsm2s Fsm3comb Fsm3onehot Fsm3 Fsm3s Design a Moore FSM 写在前面 HDLBits 刷题来到了最为重要的一部分---有限状态机,都说 Verilog 设计的精髓就是状态机的设计,可见状态机设计的重…...

【接口协议】FPGA 驱动 VGA 显示实验(二)实验设计部分

目录 实验任务 实验环境 实验设计 程序设计 VGA 时序模块 模块框图 仿真波形 顶层模块 约束文件 实验任务 利用FPGA驱动VGA实现彩条显示,分辨率为800 60060Hz,分别显示三种颜色。 实验环境 开发环境:vivado 2021.2 FPGA 器件&a…...

【接口协议】FPGA 驱动 VGA 显示实验(一)原理部分

目录 VGA介绍 VGA 接口管脚 VGA 色彩原理 VGA 工作原理 VGA 时序 VGA介绍 VGA(Video Graphics Array)视频图形阵列是 IBM 于 1987 年提出的一个使用模拟信号的电脑显示标准。VGA 接口即电脑采用 VGA 标准输出数据的专用接口。VGA 接口共有 15 针&am…...

COMSOL单相变压器温度场三维模型:解析热点温度与流体流速分布

comsol单相变压器温度场三维模型,可以得到变压器热点温度,流体流速分布 搞变压器温度场仿真最头疼的就是三维流固耦合。去年做配电变压器温升项目时,硬是跟COMSOL死磕了两周才摸到门道。今天给大家分享下怎么用非等温流接口抓取热点温度和油…...

【牛客网刷题】VL3 奇偶校验

👉 写在前面 👉 本系列博客记录牛客网刷题记录 👉 日拱一卒,功不唐捐! 目录 题目描述 奇偶校验 题目分析 仿真结果 题目描述 现在需要对输入的32位数据进行奇偶校验,根据sel输出校验结果(1输出奇校验&a…...

【牛客网刷题】VL2 异步复位的串联T触发器

👉 写在前面 👉 本系列博客记录牛客网刷题记录 👉 日拱一卒,功不唐捐! 目录 题目描述 题目分析 Verilog 代码 testbench 代码 仿真结果 题目描述 用verilog实现两个串联的异步复位的T触发器的逻辑&#x…...

minio安装 后台自启动

1:下载miniowget https://dl.min.io/server/minio/release/linux-amd64/minio2:授权chmod x minio3:设置开机自启动进入该目录下cd /etc/systemd/system/ 创建minio.service文件1: cd /etc/systemd/system/ 2:touch mi…...

【BBF系列协议】Data Models Library数据模型库设计与实现

目录Data Models Library (dmlib)dmlib的设计dmlib 的代码结构:dmlib 主要数据结构操作上下文对象(dmctx)对象定义(DMOBJ)参数定义(DMLEAF)多实例遍历函数实现(browseinstobj)参数树…...

基于JS实现的鸿蒙游戏——二十四点纸牌

目录 前言 概述 正式开始 一、创建项目 二、编码 1.项目结构 2.实现思路 3.主要代码块 三、页面及功能展示 1.运算正确 2.运算错误 3.换一批及重置 本人项目仓库链接 前言 相信大家都有玩过纸牌游戏,本项目是基于JS实现的鸿蒙小游戏二十四点纸牌&…...

vue截取字符串(商城系统非常常用的小知识)

1.截取指定字符串{{row.real_name.substr(2, 3)}}2.截取字符串最后一位{{row.real_name.charAt(row.real_name.length - 1)}}3.看一下效果如何...

【BBF系列协议】TR-140 TR-069支持存储服务的设备的数据模型

目录TR-140 TR-069支持存储服务的设备的数据模型执行摘要1.目的和范围目的范围2 案例2.1 BASIC MANAGED STORAGE SERVICE(基本托管存储服务)2.2 REMOTE STORAGE BACK-UP SERVICE(远程存储备份服务)2.3 Remote access of Storage S…...

【BBF系列协议】TR-135 支持TR-069的STB的数据模型

TR-135 支持TR-069的STB的数据模型 执行摘要 TR-135,启用TR-069的STB的数据模型,定义了用于通过TR-069和TR-106中定义的CWMP远程管理机顶盒(STB)设备上的数字电视(IPTV或广播)功能的数据模型。它包括用于…...

【BBF系列协议】TR-106 CWMP端点和USP代理的数据模型模板

目录TR-106 CWMP端点和USP代理的数据模型模板执行摘要1 介绍CWMPUSP规范结构2 架构2.1 数据层次结构2.2 对象版本控制2.3 配置文件2.4 DEPRECATED 和 OBSOLETED 条目3 对象定义3.1 通用符号3.2 数据类型和表示3.3 供应商特定要素A参数:单个实例对象:单个命令:单个事…...

【亲测免费】【推荐】基于Vue3的全能H5模板:vue3-h5-template

标题:【推荐】基于Vue3的全能H5模板:vue3-h5-template 【免费下载链接】vue3-h5-template My starter template for Vue3, with vite, quark design, sass(含viewport 适配方案, axios 封装) 项目地址: https://gitcode.com/gh_mirrors/vue3/vue3-h5-t…...

Scalding执行模型揭秘:从Job到Execution的演进之路

Scalding执行模型揭秘:从Job到Execution的演进之路 【免费下载链接】scalding A Scala API for Cascading 项目地址: https://gitcode.com/gh_mirrors/sc/scalding Scalding是一个基于Scala的Cascading API,专为大规模数据处理而设计。这个强大的…...

探索DockerGS:一键启动动漫游戏服务器的利器

探索DockerGS:一键启动动漫游戏服务器的利器 【免费下载链接】DockerGS DockerGC is a container that run Grasscutter (anime game) with just a single command. 项目地址: https://gitcode.com/gh_mirrors/do/DockerGS 在数字娱乐的世界中,各…...

推荐项目:IdentityServer4.AccessTokenValidation - 混合型JWT和参考令牌验证利器

推荐项目:IdentityServer4.AccessTokenValidation - 混合型JWT和参考令牌验证利器 【免费下载链接】IdentityServer4.AccessTokenValidation IdentityServer Access Token Validation for ASP.NET Core 项目地址: https://gitcode.com/gh_mirrors/id/IdentityServ…...

推荐:用Flowershow打造你的优雅知识分享网站

推荐:用Flowershow打造你的优雅知识分享网站 【免费下载链接】flowershow 💐 Publish your obsidian digital garden or any markdown site easily and elegantly. 项目地址: https://gitcode.com/gh_mirrors/fl/flowershow 1、项目介绍 &#x…...

RITM 交互式分割项目使用教程

RITM 交互式分割项目使用教程 【免费下载链接】ritm_interactive_segmentation 项目地址: https://gitcode.com/gh_mirrors/rit/ritm_interactive_segmentation 1. 项目的目录结构及介绍 RITM 交互式分割项目的目录结构如下: ritm_interactive_segmentati…...

RITM交互式分割算法实战指南

RITM交互式分割算法实战指南 【免费下载链接】ritm_interactive_segmentation 项目地址: https://gitcode.com/gh_mirrors/rit/ritm_interactive_segmentation 项目介绍 RITM(Real-Time Interactive Image Segmentation with Memory-Augmented U-Net&#…...