多线程的实现


实现多线程的三个方式
1、继承Thread类
2、实现Runnable接口
3、实现Callable接口
在这里插入图片描述

Thread

Thread其实是实现了Runnable接口,而线程类,直接继承Thread,重写run编写线程体,创建线程对象,调用start()
在这里插入图片描述

输出信息测试

/**
 * 创建多线程方式1,继承Thread类,重新run方法,调用start开启线程
 * 线程不一定立即执行,CPU调度
 */
public class TestThread1 extends Thread {

    @Override
    public void run() {
        //run方法线程体
        for(int i=0;i<20;i++){
            System.out.println("run方法:"+i);
        }
    }

    public static void main(String[] args) {


        //创建线程对象
        TestThread1 thread1=new TestThread1();
        //调用start开启线程
        thread1.start();

        //main主线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("main方法:"+i);
        }



    }
}

可以看到结果,交替执行的,而不是按照顺序执行
在这里插入图片描述

下载网络图片测试

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * thread多线程同步下载图片
 */
public class TestThread2 extends Thread {

    //网络图片地址
    private String url;
    //保存的文件名
    private String name;

    public TestThread2(String url,String name){

        this.name=name;
        this.url=url;

    }


    //下载图片的执行体
    @Override
    public void run() {

        WebDownloader webDownloader=new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);

    }

    public static void main(String[] args) {
        TestThread2 thread1=new TestThread2("https://img-blog.csdnimg.cn/20200430094021144.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2EzNTYyMzIz,size_16,color_FFFFFF,t_70","C:\\Users\\w4523\\Desktop\\PigchaClient_green\\1.jpg");
        TestThread2 thread2=new TestThread2("https://img-blog.csdnimg.cn/208f9b580ef948b69b512083345e4600.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAV3VXdUlJ,size_20,color_FFFFFF,t_70,g_se,x_16","C:\\Users\\w4523\\Desktop\\PigchaClient_green\\2.jpg");
        TestThread2 thread3=new TestThread2("https://img-blog.csdnimg.cn/f9c8745d07db43f286da8b7ea7562ea0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAV3VXdUlJ,size_20,color_FFFFFF,t_70,g_se,x_16","C:\\Users\\w4523\\Desktop\\PigchaClient_green\\3.jpg");

        //先执行thread1
        thread1.start();
        //再执行thread2
        thread2.start();
        //最后执行thread3
        thread3.start();


    }

}

//下载器
class WebDownloader{

    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,downloader异常");
        }
    }

}

可以看到,方法的先后顺序是thread1、thread2、thread3。实际执行顺序是1、3、2,其实是多线程同步执行的,具体顺序是cpu执行
在这里插入图片描述

Runnable

在这里插入图片描述

/**
 * 创建多线程方式2,实现Runnable接口,重写run方法,执行线程丢入runnable接口实现类,调用start
 */
public class TestThread3 implements Runnable {


    @Override
    public void run() {
        //run方法线程体
        for(int i=0;i<20;i++){
            System.out.println("run方法:"+i);
        }
    }

    public static void main(String[] args) {

        //创建runnable接口的实现类对象
        TestThread3 thread3=new TestThread3();

        //创建线程对象,通过线程对象开启线程,
        new Thread(thread3).start();

        //main主线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("main方法:"+i);
        }



    }




}

Thread和Runnable

在这里插入图片描述

  • 实现多线程:

    • Thread是通过继承类的方式来做多线程,只能实现一个类,
    • Runnable是通过实现接口的方式做多线程,可以继承多个接口,
  • 启动线程

    • 继承Thread的类,通过类对象.start()启动
    • 实现Runnable的接口,还是需要new一个Thread,通过new Thread(实现接口的类).start()启动;

推荐使用Runnable,避免了单继承的局限性,可以被多个线程使用

多线程并发

/**
 * 多个线程操作同一个对象
 * 买火车票例子
 * 问题:多线程情况下,操作同一个资源,线程不安全,数据紊乱
 */
public class TestThread4 implements Runnable {

    //票数
    int ticketNums=10;

    @Override
    public void run() {
        while (true){

            if(ticketNums<=0){
                break;
            }

            System.out.println(Thread.currentThread().getName()+"--->拿到第"+ticketNums--+"张票");
        }
    }

    public static void main(String[] args) {
        TestThread4 thread4=new TestThread4();
        new Thread(thread4,"张三").start();
        new Thread(thread4,"李四").start();
        new Thread(thread4,"王五").start();

    }


}

通过runnable实现多线程,发现变量值在多线程的情况下,被多个线程共用了,数据不一致,肯定是不允许的
在这里插入图片描述

Callable

在这里插入图片描述

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

/**
 * 线程创建方式3,实现callable接口
 * 好处:可以获取返回值
 *      可以抛出异常
 */
public class TestCallable implements Callable<Boolean> {

    //网络图片地址
    private String url;
    //保存的文件名
    private String name;

    public TestCallable(String url,String name){

        this.name=name;
        this.url=url;

    }


    //下载图片的执行体
    @Override
    public Boolean call() {

        WebDownloader webDownloader=new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载了文件名为:"+name);

        return true;

    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestCallable thread1=new TestCallable("https://img-blog.csdnimg.cn/20200430094021144.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2EzNTYyMzIz,size_16,color_FFFFFF,t_70","C:\\Users\\w4523\\Desktop\\PigchaClient_green\\1.jpg");
        TestCallable thread2=new TestCallable("https://img-blog.csdnimg.cn/208f9b580ef948b69b512083345e4600.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAV3VXdUlJ,size_20,color_FFFFFF,t_70,g_se,x_16","C:\\Users\\w4523\\Desktop\\PigchaClient_green\\2.jpg");
        TestCallable thread3=new TestCallable("https://img-blog.csdnimg.cn/f9c8745d07db43f286da8b7ea7562ea0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAV3VXdUlJ,size_20,color_FFFFFF,t_70,g_se,x_16","C:\\Users\\w4523\\Desktop\\PigchaClient_green\\3.jpg");

        //创建执行服务
        ExecutorService ser= Executors.newFixedThreadPool(3);
        //提交执行
        Future<Boolean> result1=ser.submit(thread1);
        Future<Boolean> result2=ser.submit(thread2);
        Future<Boolean> result3=ser.submit(thread3);
        //获取结果
        boolean sr1=result1.get();
        boolean sr2=result2.get();
        boolean sr3=result3.get();
        //关闭服务
        ser.shutdownNow();



    }

    //下载器
    class WebDownloader{

        //下载方法
        public void downloader(String url,String name){
            try {
                FileUtils.copyURLToFile(new URL(url),new File(name));
            } catch (IOException e) {
                e.printStackTrace();
                System.out.println("IO异常,downloader异常");
            }
        }

    }

}

多线程执行成功
在这里插入图片描述

lamda表达式

函数式接口

在这里插入图片描述
任何接口,只包含一个抽象方法,他就是函数式接口,可以通过lambda表达式来创建接口对象

  1. 接口实现的几种方式
/**
 * lambda表示
 */
public class TestLambda {

    //3、静态内部类
    static class Like2 implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda2");
        }
    }

    public static void main(String[] args) {
        ILike like=new Like();
        like.lambda();

        like=new Like2();
        like.lambda();

        //4、局部内部类
        class Like3 implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda3");
            }
        }

        like=new Like3();
        like.lambda();

        //5、匿名内部类
        like=new ILike() {
            @Override
            public void lambda() {
                System.out.println("i like lambda4");
            }
        };

        like.lambda();

        //6、lambada简化
        like=()-> {
            System.out.println("i like lambda5");
        };
        like.lambda();

    }


}

//1、定义一个函数式接口
interface ILike{
    void lambda();
}

//2、实现类
class Like implements ILike{
    @Override
    public void lambda() {
        System.out.println("i like lambda");
    }
}
  1. 简化lambda
/**
 * 总结:前提必须是函数式接口
 *      lambda如果只有一行代码,才能简化花括号,如果有多行,就得用代码块
 *      多个参数也可以去掉参数类型
 */
public class TestLambda2 {

    public static void main(String[] args) {
        Ilove love=null;

        //1、简化参数类型
        love=(a)->{
            System.out.println(a);
        };
        love.love(11111);
        //2、简化括号
        love=a->{
            System.out.println(a);
        };
        love.love(222222);
        //3、简化花括号
        love=a-> System.out.println(a);

        love.love(333333333);
    }

}

interface Ilove{
    void love(int a);
}

线程的五大状态

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

线程停止

在这里插入图片描述
stop或destroy已经建议不再使用,通过自己设置标志位让线程停止

/**
 * 测试停止线程
 * 1.建议线程正常停止,利用次数,不建议死循环
 * 2、建议使用标志位,设置一个标志位
 * 3、不要使用stop或destroy等过时的或JDK不建议使用的方法
 */
public class TestStop implements Runnable {

    //1、设置一个标志位
    private boolean flag=true;

    @Override
    public void run() {
        int i=0;
        while (flag){
            System.out.println("线程正在运行。。。。。。。。。Thread"+i++);
        }

    }

    //2、设置一个公开的方法转换停止线程,转换标志位
    public void stop(){
        this.flag=false;
    }

    public static void main(String[] args) {
        TestStop stop=new TestStop();
        new Thread(stop).start();


        for (int i = 0; i < 1000; i++) {
            System.out.println("main"+i);
            if(i==900){
                //调用stop方法切换标志位,让线程停止
                stop.stop();
                System.out.println("线程该停止了");
            }
        }

    }
}

线程休眠

在这里插入图片描述
sleep时间单位是毫秒

线程礼让

yield让当前正在执行的线程暂停,但不阻塞,从运行状态变为就绪状态
在这里插入图片描述
两个就绪状态的线程,线程A和线程B,假如A已经进入cpu运行了,B还是就绪状态,通过yield让线程A变成就绪状态 ,重新等待进入cpu,有可能还是A进入,进入了就继续执行,也有可能B进入,结果不一定

/**
 * 测试礼让,
 * 礼让不一定成功
 */
public class TestYield {

    public static void main(String[] args) {
        MyYield myYield=new MyYield();
        new Thread(myYield,"A").start();
        new Thread(myYield,"B").start();

    }


}

class MyYield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程开始执行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"线程停止执行");
    }
}

A还没执行完,礼让以后,B线程就开始执行了,B执行完,A继续执行
在这里插入图片描述

join

类似于插队,先执行这个线程,其它线程都阻塞,等这个线程执行完了,其它 线程才能继续执行

/**
 * 测试join
 * 类似于插队
 */
public class TestJoin implements Runnable {


    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("线程"+Thread.currentThread().getName()+"-------->"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //启动线程
        TestJoin testJoin=new TestJoin();
        Thread thread = new Thread(testJoin,"A");
        thread.start();

        //主线程
        for (int i = 0; i < 1000; i++) {
            //主线程和线程A同时进行,当主线程进行到200时线程A就插队,线程A执行完再执行主线程
            if(i==200){
                thread.join();//插队
            }
            System.out.println("main->"+i);

        }


    }

}

观测线程状态

NEW 尚未启动
RUNNABLE 正在执行中
BLOCKED 阻塞的(被同步锁或者IO锁阻塞)
WAITING 永久等待状态
TIMED_WAITING 等待指定的时间重新被唤醒的状态
TERMINATED 执行完成

/**
 * 观察测试线程状态
 */
public class TestState {

    public static void main(String[] args) throws InterruptedException {
        Thread thread=new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("线程执行完成");
        });

        //观察没有调用的Thread状态
        System.out.println("观察没有调用的Thread状态-->"+thread.getState());

        thread.start();
        //观察调用start的Thread状态
        System.out.println("观察调用start的Thread状态-->"+thread.getState());

        while (thread.getState()!=Thread.State.TERMINATED){
            Thread.sleep(100);
            //线程不停止就一直输出状态
            System.out.println("线程不停止就一直输出状态-->"+thread.getState());
        }

    }

}

线程优先级

在这里插入图片描述

/**
 * 测试线程优先级
 */
public class TestPriority {

    public static void main(String[] args) {
        //查看主线程默认优先级
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());

        MyPriority myPriority=new MyPriority();
        Thread thread1=new Thread(myPriority,"thread1");
        Thread thread2=new Thread(myPriority,"thread2");
        Thread thread3=new Thread(myPriority,"thread3");
        Thread thread4=new Thread(myPriority,"thread4");
        Thread thread5=new Thread(myPriority,"thread5");
        Thread thread6=new Thread(myPriority,"thread6");

        //先设置优先级再启动
        thread1.start();

        thread2.setPriority(1);
        thread2.start();

        thread3.setPriority(4);
        thread3.start();

        thread4.setPriority(Thread.MAX_PRIORITY);
        thread4.start();

        thread5.setPriority(7);
        thread5.start();

        thread6.setPriority(8);
        thread6.start();



    }


}
class MyPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }
}

守护线程

线程分为用户线程和守护线程,
虚拟机确保用户线程执行完毕。
虚拟机不用等待守护线程执行完毕。

/**
 * 测试守护线程
 */
public class TestDaemon {


    public static void main(String[] args) {
        God god=new God();

        You you=new You();


        Thread thread=new Thread(god);
        thread.setDaemon(true);     //默认false,表示用户线程,一般的线程都是用户线程

        thread.start(); //守护线程启动

        new Thread(you).start();




    }



}

class God implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("守护线程运行中");
        }
    }
}

class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("用户线程运行中");
        }
        System.out.println("用户线程结束");
    }
}

线程同步

synchronized

在这里插入图片描述
锁的对象就是变化的量,需要增删改的对象
可以给代码块或方法加锁

死锁

在这里插入图片描述
在这里插入图片描述
尽量避免锁的嵌套使用,避免一个进程获取多个锁

Lock锁

在这里插入图片描述

    //定义lock锁
    private ReentrantLock lock=new ReentrantLock();
	try {
	    lock.lock();    //加锁
		//方法。。。。。。.。。
	}catch (Exception e){
	
	}finally {
	    lock.unlock();      //解锁
	}

synchronized和Lock对比

Lock是显式锁,需要手动开启手动关闭,synchronized是隐式锁,出了作用域自动释放
Lock只能锁代码块,synchronized可以锁代码块和方法
Lock锁,JVM花费较少的时间来调度线程,性能更好,并且更好扩展性(提供更多子类)
优先使用顺序:Lock>同步代码块>同步方法

线程协作

在这里插入图片描述

线程池

在这里插入图片描述

/**
 * 测试线程池
 *
 */
public class Pool {

    public static void main(String[] args) {
        /**
         * 1、创建服务,创建线程池
         * newFixedThreadPool参数是线程池大小
         */
        ExecutorService service= Executors.newFixedThreadPool(10);

        //执行
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());

        //2、关闭连接
        service.shutdown();


    }

}

class MyThread implements Runnable{

    @Override
    public void run() {
            System.out.println(Thread.currentThread().getName());
    }
}

在这里插入图片描述

回顾

实现线程的三种方式

/**
 * 回顾总结线程的创建
 */
public class ThreadNew {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        new MyThread1().start();
        new Thread(new MyThread2()).start();
        FutureTask<Integer> futureTask=new FutureTask(new MyThread3());
        new Thread(futureTask).start();
        Integer integer = futureTask.get();
        System.out.println(integer);
    }



}

//1、继承Thread类
class MyThread1 extends Thread{
    @Override
    public void run() {
        System.out.println("MyThread1");
    }
}

//2、实现Runnable接口
class MyThread2 implements Runnable{

    @Override
    public void run() {
        System.out.println("MyThread2");
    }
}

//3、实现Callable接口
class MyThread3 implements Callable{

    @Override
    public Integer call() throws Exception {
        System.out.println("MyThread3");
        return 100;
    }
}

线程池按照顺序执行

把线程池数量设为1,就会按照获取线程的顺序执行了

    @Test
    public void test1(){
        ExecutorService service = Executors.newFixedThreadPool(1);
        service.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread1");
            }
        });
        service.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread2");
            }
        });
        service.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread4");
            }
        });
        service.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread5");
            }
        });
        service.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread6");
            }
        });
    }

在这里插入图片描述

CountDownLatch

countDownLatch.await()会阻塞调用线程直到 state==0。因此,可以利用这个特性使得子线程按序执行

private static CountDownLatch countDownLatch = new CountDownLatch(1);

    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t1 do something");
                countDownLatch.countDown();
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t2 do something");
                countDownLatch.countDown();
            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("t3 do something");
                countDownLatch.countDown();
            }
        });

        t1.start();
        // 主线程阻塞等待子线程执行完毕
        countDownLatch.await();
        t2.start();
        // 主线程阻塞等待子线程
        countDownLatch.await();
        t3.start();
        // 主线程阻塞等待子线程
        countDownLatch.await();
        }

Future

Future模式是多线程开发中常用的一种设计模式,它的核心思想是异步调用。有时候不需要立刻返回执行结果,先让它执行,我们做其它的工作。等要用的时候,再尝试获取它的执行结果。类似于ajax的同步异步。
可以配合Callable使用,获取返回结果。以及对线程的一些操作,取消线程操作或者判断是否完成等。

Future的5个主要方法

get()

主要用来获取Callable的执行结果。

Callable执行完成:立刻返回执行结果
Callable未开始或者进行中:阻塞并等待线程执行完成

    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(20);
        Future<Integer> future = service.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                return 111111;
            }
        });
        try {
            //获取结果
            Integer integer = future.get();
            System.out.println("返回结果:"+integer);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            service.shutdown();
        }
    }

返回结果接收成功
在这里插入图片描述

get(long timeout,TimeUnit unit)

超时取消任务

传入一个时间,如果时间到了,还没执行完成,就会抛出TimeoutExceptionget,然后取消任务

public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(20);
        Future<Integer> future = service.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                //先睡眠5s
                Thread.sleep(5000);
                return 111111;
            }
        });
        try {
            //获取结果
            Integer integer = future.get(3,TimeUnit.SECONDS);
            System.out.println("返回结果:"+integer);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            service.shutdown();
        }
    }

线程执行时间为5s,get的时间设置为3s,因为超出设置的时间,抛出java.util.concurrent.TimeoutException异常
在这里插入图片描述

cancel()

boolean cancel(boolean mayInterruptIfRunning);
取消执行相关线程,参数为boolean值,

为 true ,则线程将被中断,任务将被取消
为 false ,则仅当任务尚未开始执行时才会取消任务
任务取消后,其状态设置为 CANCELLED ,并调用 done 方法来指示任务已完成

		//创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(1);
        //执行线程
        Future future = executor.submit(new MyThread3());

        future.cancel(boolean)

isDone()

检查任务是否已完成或已取消。如果任务已完成或已取消,则该方法返回 true ;否则,返回 false 。

    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(20);
        Future<Integer> future = service.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                //先睡眠5s
                Thread.sleep(5000);
                return 111111;
            }
        });
        try {
            //查看线程状态,如果未执行完,等待1s后再查看线程状态
            while (!future.isDone()){
                System.out.println("未完成,等待1s");
                Thread.sleep(1000);
            }
            //线程状态
            System.out.println(future.isDone());
            //获取结果
            Integer integer = future.get();
            System.out.println("返回结果:"+integer);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            service.shutdown();
        }
    }

5s后执行线程结束
在这里插入图片描述

isCanaelled()

检查任务是否已取消。如果任务已取消,则该方法返回 true ;否则,返回 false 。

public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(20);
        Future<Integer> future = service.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                //先睡眠5s
                Thread.sleep(5000);
                return 111111;
            }
        });
        try {
            int num=0;
            //查看线程状态,如果未执行完,等待1s后再查看线程状态
            while (!future.isDone()){
                num++;
                System.out.println("未完成,等待1s");
                if(num==3){
                    //超过3s,取消线程
                    future.cancel(true);
                }
                System.out.println("线程是否取消:"+future.isCancelled());
                Thread.sleep(1000);
            }
            //获取结果
            Integer integer = future.get();
            System.out.println("返回结果:"+integer);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            service.shutdown();
        }
    }

获取结果的时候抛出异常java.util.concurrent.CancellationException,因为线程已经被取消了
在这里插入图片描述

CountDownLatch

CountDownLatch是一个非常有用的工具,它可以用来确保在所有线程都执行完毕后才执行后续操作。它在许多并发编程场景中都有应用,比如等待所有子线程执行完毕后再关闭主线程,等待所有数据库操作执行完毕后再提交事务等等。

public static void main(String[] args) {
        // 创建一个CountDownLatch,初始值为3
        CountDownLatch latch = new CountDownLatch(3);

        // 创建三个线程,每个线程都将调用countDown()方法
        Thread t1 = new Thread(() -> {
            try {
                // 模拟耗时操作
                Thread.sleep(1000);
                // 调用countDown()方法
                latch.countDown();
                System.out.println(Thread.currentThread()+"执行完成");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread t2 = new Thread(() -> {
            try {
                // 模拟耗时操作
                Thread.sleep(2000);
                // 调用countDown()方法
                latch.countDown();
                System.out.println(Thread.currentThread()+"执行完成");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread t3 = new Thread(() -> {
            try {
                // 模拟耗时操作
                Thread.sleep(3000);
                // 调用countDown()方法
                latch.countDown();
                System.out.println(Thread.currentThread()+"执行完成");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 启动三个线程
        t1.start();
        t2.start();
        t3.start();

        // 等待三个线程都执行完毕
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 三个线程都执行完毕后,执行后续操作
        System.out.println("所有线程都执行完毕");
    }

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值