Java-多线程解析1

news2024/11/24 14:50:25

一、线程的描述:

        1、线程是一个应用程序进程中不同的执行路径比例如:一个WEB服务器,能够为多个用户同时提供请求服务;而 -> 进程是操作系统中正在执行的不同的应用程序,比如:我们可以同时打开系统的word和游戏

        2、多线程随处不在,例如:平常用电脑办公的时候,一边听着歌一边做事,此时电脑的状态就是多线程;向平常玩手机看直播的时候,一边看着直播,一边聊着WX,此时手机的状态就是多线程;提高了用户的体验度以及画面的效应速率,生活中随处可见;

        3、三大特性:

                3.1、原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作(Atomic、CAS算法、synchronized、Lock)

                3.2、可见性:一个主内存的线程如果进行了修改,可以及时被其他线程观察到(synchronized、volatile)

                3.3、有序性:如果两个线程不能从 happens-before原则 观察出来,那么就不能观察他们的有序性,虚拟机可以随意的对他们进行重排序,导致其观察观察结果杂乱无序(happens-before原则)


二、线程的作用:

        1、举例说:把一个人花费30天完成的事情 变成10个人化3天就能完成,目的时为了提高程序的效率

        2、为了解决CPU利用率问题,提高CPU利用

        3、平时开发的时候,点击某一个操作时,通过同一个条件访问2个接口,将结果数据展示到页面;

                3.1、传统的做法:按照顺序依次访问2个接口,那么数据最后展示的时间就是2个接口返回结果总和;

                3.2、异多线程做法:将方法放入异步线程中,线程启动后就去抢CPU执行权,谁先拿到谁先执行,线程同时发起请求,数据的执行时间= 其中某个线程返回结果的最长的时间;

                3.3、同步多线程:

                        synchronized 是Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。


三、线程的生命周期:


四、线程的实现方式:

        有三种:继承Thread类实现Runnable接口实现Callable接口(不常用)


1、继承Thread方式

        1-1:继承Thread类,重写run方法;

        1-2:线程启动后,谁先抢到CPU执行权,谁就先执行

public class JavaStudyThread extends Thread {

    public JavaStudyThread(String name) {
        super(name);
    }

    //自定义线程对象,继承Thread,重写run()方法
    @Override
    public void run() {
        // 线程执行体
        for (int i = 1; i < 3; i++) {
            System.out.println("公平竞争->"+Thread.currentThread().getName() + "--" + "主动出击" + i + "次,得到了我");
        }
    }

    public static void main(String[] args) {
        //创建线程实现类对象,调用start()方法启动线程
        new JavaStudyThread("小老婆1").start();
        new JavaStudyThread("小老婆2").start();
        for (int i = 1; i < 6; i++) {
            System.out.println("公平竞争->"+"大老婆--" + "主动出击" + i + "次,得到了我");
        }
    }
}

输出结果:说明谁抢到主动权,谁就可以先拥有我

公平竞争->大老婆--主动出击1次,得到了我
公平竞争->小老婆2--主动出击1次,得到了我
公平竞争->小老婆1--主动出击1次,得到了我
公平竞争->大老婆--主动出击2次,得到了我
公平竞争->小老婆2--主动出击2次,得到了我
公平竞争->小老婆1--主动出击2次,得到了我
公平竞争->大老婆--主动出击3次,得到了我
公平竞争->大老婆--主动出击4次,得到了我
公平竞争->大老婆--主动出击5次,得到了我


        2、实现Runnable接口:

        2-1:实现Runnable接口,重写run方法

        2-2:谁先抢到CPU执行权,谁就先执行

public class JavaStudyThread implements Runnable {

    // 自定义线程对象,实现Runnable接口,重写run()方法
    @Override
    public void run() {
        for (int i = 1; i < 3; i++) {
            System.out.println("公平竞争->"+Thread.currentThread().getName() + "--" + "主动出击" + i + "次,得到了我");
        }
    }

    public static void main(String[] args) {
        // 创建实现类对象
        JavaStudyThread javaStudyThread = new JavaStudyThread();
        // 创建代理类对象
        Thread thread = new Thread(javaStudyThread,"小老婆1");
        Thread thread2 = new Thread(javaStudyThread,"小老婆2");
        // 调用start()方法启动线程
        thread.start();
        thread2.start();
        for (int i = 1; i < 6; i++) {
            System.out.println("公平竞争->"+"大老婆--" + "主动出击" + i + "次,得到了我");
        }
    }
}

输出结果:说明谁抢到主动权,谁就可以先拥有我

公平竞争->大老婆--主动出击1次,得到了我
公平竞争->小老婆1--主动出击1次,得到了我
公平竞争->大老婆--主动出击2次,得到了我
公平竞争->小老婆1--主动出击2次,得到了我
公平竞争->小老婆2--主动出击1次,得到了我
公平竞争->小老婆2--主动出击2次,得到了我
公平竞争->大老婆--主动出击3次,得到了我
公平竞争->大老婆--主动出击4次,得到了我
公平竞争->大老婆--主动出击5次,得到了我


        3、实现Callable接口(不常用)

        3-1:实现Callable接口,定义返回值类型

        3-2:重写call()方法,并抛出异常

        3-3:谁先抢到CPU执行权,谁就先执行

public class JavaStudyThread implements Callable<Boolean> {

    @Override
    public Boolean call() throws Exception {
        for (int i = 0; i < 4; i++) {
            System.out.println("自定义" + Thread.currentThread().getName() + "->" + i);
        }
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 创建实现类对象
        JavaStudyThread thread = new JavaStudyThread();
        JavaStudyThread thread2 = new JavaStudyThread();

        // 创建执行服务,参数是线程池线程数量
        ExecutorService ser = Executors.newFixedThreadPool(2);
        // 提交执行
        Future<Boolean> res = ser.submit(thread);
        Future<Boolean> res2 = ser.submit(thread2);

        // 获取结果
        boolean r1 = res.get();
        boolean r2 = res2.get();
        // 关闭服务
        ser.shutdownNow();
    }
    /*输出结果:
        自定义pool-1-thread-2->0
        自定义pool-1-thread-2->1
        自定义pool-1-thread-2->2
        自定义pool-1-thread-1->0
        自定义pool-1-thread-1->1
        自定义pool-1-thread-2->3
        自定义pool-1-thread-1->2
        自定义pool-1-thread-1->3
    */
}

五、多线程常用的一些控制方法:

         在这里插入图片描述

sleep方法:同步(synchronized

        设定线程阻塞的时间,先让从“运行状态”进入到“休眠(阻塞)状态”,等待设定的时间过去,从“(阻塞)状态”变成“就绪状态” 每一个对象都有一个锁,sleep不会释放锁
public class JavaStudyThread implements Runnable{
    private int count = 20;
    public void run() {
        while (true) {
            if (count <= 0) {
                System.out.println("已卖完");
                return;
            }
            getCount();
        }
    }
    public synchronized void getCount() {
        if(count==0){
            System.out.println("已卖完");
            return;
        }
        System.out.println(Thread.currentThread().getName() + "-->售出第:" + (21 - count) + "票");
        count--;
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args){
        JavaStudyThread t1 = new JavaStudyThread();
        Thread thread= new Thread(t1);
        Thread thread1= new Thread(t1);
        thread.start();
        thread1.start();
    }
}

wait方法:

        设定线程阻塞的时间,先让从“运行状态”进入到“休眠(阻塞)状态”,释放同步锁,等待设定的时间过去,从“(阻塞)状态”变成“就绪状态” 每一个对象都有一个锁;
public class JavaStudyThread {
    private static String str = "test";

    public void run() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (str) {
                    while (true) {
                        try {
                            System.out.println(str);
                            str.wait();
                            System.out.println(str);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();
    }

    public static void main(String[] args) {
        new JavaStudyThread().run();
        System.out.println("111111");
    }
}

yield方法:

        - 提出申请释放CPU资源,至于能否成功释放取决于JVM决定。
        - 调用yield()方法后,线程仍然处于RUNNABLE状态,线程不会进入阻塞状态。
        - 调用yield()方法后,线程处于RUNNABLE状态,就保留了随时被调用的权利。
        - 第一种:a/b线程释放CPU,a/b线程抢到CPU执行释放,a/b线程抢到了CPU执行权;
        - 第二种:a/b的所有线程执行完才释放CPU,此时a/b线程抢到CPU继续执行;
public class JavaStudyThread implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "--得到了我");
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + "--连续--得到了我");
    }

    public static void main(String[] args) {
        //创建实现类对象
        JavaStudyThread javaStudyThread = new JavaStudyThread();
        //创建线程
        Thread thread = new Thread(javaStudyThread, "大老婆");
        Thread thread1 = new Thread(javaStudyThread, "小老婆");
        //启动线程
        thread.start();
        thread1.start();
    }
}

输出结果:

        1.从结果1看,小老婆释放CPU成功后,大老婆就抢到了CPU执行权,接着大老婆也释放CPU成功,小老婆抢到了CPU执行权;
        2.从结果2看,小老婆并没有成功释放CPU,而是连续得到了我;
结果1:
	小老婆--得到了我
	大老婆--得到了我
	小老婆--连续--得到了我
	大老婆--连续--得到了我
	
结果2:
	小老婆--得到了我
	小老婆--连续--得到了我
	大老婆--得到了我
	大老婆--连续--得到了我

join方法:

        - 将当前的线程挂起,当前线程阻塞,待其他的线程执行完毕,当前线程才能执行。
        - 可以把join()方法理解为插队,谁插到前面,谁先执行。
        - 如果主线程阻塞,等待 join线程 一口气执行完,主线程才能继续执行。
public class JavaStudyThread implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "join()线程执行:" + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //创建实现类对象
        JavaStudyThread javaStudyThread = new JavaStudyThread();
        //创建线程
        Thread thread = new Thread(javaStudyThread, "a");
        //启动线程
        thread.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("主线程执行:" + i);
            if (i == 2) {
                thread.join();//主线程阻塞,等待thread一口气执行完,主线程才能继续执行
            }
        }
    }
}

setPriority方法:

        - 改变、获取线程的优先级。
        - Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。
        - 线程的优先级用数据表示,范围1~10。
        - 线程的优先级高只是表示他的权重大,获取CPU执行权的几率大。
        - 先设置线程的优先级,在执行start()方法。
        - 优先级高的线程不一定先执行。
public class JavaStudyThread implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "线程优先级:" + Thread.currentThread().getPriority());
    }

    public static void main(String[] args) {
        //创建实现类对象
        JavaStudyThread javaStudyThread = new JavaStudyThread();
        //创建线程
        Thread thread = new Thread(javaStudyThread, "a");
        Thread thread1 = new Thread(javaStudyThread, "b");
        Thread thread2 = new Thread(javaStudyThread, "c");
        Thread thread3 = new Thread(javaStudyThread, "d");

        //先设置线程的优先级
        thread.setPriority(Thread.MIN_PRIORITY);//1
        thread1.setPriority(Thread.NORM_PRIORITY);//5
        thread2.setPriority(Thread.MAX_PRIORITY);//10
        thread3.setPriority(7);
        //启动线程
        thread.start();
        thread1.start();
        thread2.start();
        thread3.start();
    }
    //    执行结果:优先级高的线程不一定先执行
    //        c线程优先级:10
    //        b线程优先级:5
    //        a线程优先级:1
    //        d线程优先级:8

}

setDaemon()方法:

        -线程分为用户线程和守护线程。
        -虚拟机必须确保用户线程执行完毕。
        -虚拟机不用等待守护线程执行完毕。(如:后天记录操作日志、监控内存、垃圾回收等线程)。
        -Thread.setDeamon(booean on)方法,true:守护线程;fasle:用户进程。默认是false。
        -用户进行执行完毕,守护进程也就停止执行。
public class JavaStudyThread {
    public static void main(String[] args) {
        //创建实现类对象
        DeamonThread deamon = new DeamonThread();
        UserThread user = new UserThread();

        Thread thread2 =new Thread(user);
        thread2.start();

        //创建线程
        Thread thread1 = new Thread(deamon);
        thread1.setDaemon(true);
        thread1.start();

    }
}
//守护进程
class DeamonThread implements Runnable {

    @Override
    public void run() {
        // 验证虚拟机不用等待守护线程执行完毕,只要用户线程执行完毕,程序就结束。
        while (true){
            System.out.println("守护线程");
        }
    }
}
//用户进程
class UserThread implements Runnable{

    @Override
    public void run() {
        for (int i =0 ;i<2;i++) {
            System.out.println("用户线程:" + i);
        }
    }
}

isAlive方法:

        -用于检查线程是否处于活动状态。活着是指已开始但尚未终止的线程。调用run方法时,线程将运行特定的时间段,然后停止执行。
public class JavaStudyThread implements Runnable {
    @Override
    public void run(){
        System.out.println("sample ");
        try{
            Thread.sleep(25);
        }
        catch (InterruptedException ie){
        }
        System.out.println("only ");
    }
    public static void main(String[] args){
        JavaStudyThread javaStudyThread =new JavaStudyThread();
        Thread my_obj_1 = new Thread(javaStudyThread);
        Thread my_obj_2 = new Thread(javaStudyThread);
        my_obj_1.start();
        System.out.println("第一个对象已创建并启动");
        my_obj_2.start();
        System.out.println("第二个对象已创建并启动");
        System.out.println(my_obj_1.isAlive());
        System.out.println("第一个对象上的isAlive函数已被调用");
        System.out.println(my_obj_2.isAlive());
        System.out.println("第二个对象上的isAlive函数已被调用");
    }
    /*输出结果:
        第一个对象已创建并启动
        sample
        第二个对象已创建并启动
        true
        第一个对象上的isAlive函数已被调用
        true
        第二个对象上的isAlive函数已被调用
        sample
        only
        only
    */
}

六、多线程 并发 和 同步:synchronized 同步锁的使用

        1、并发:

        1-1、并发原因在多线程场景下,如果同一个资源 被多个线程修改,其他线程又读取这个资源,那么就可能存在数据结果不对的问题,也就会导致线程不安全;例如:两人卖20张票;

public class JavaStudyThread implements Runnable{
    private int count = 20;
    public void run() {
        while (true) {
            if (count <= 0) {
                System.out.println("已卖完");
                return;
            }
            getCount();
        }
    }
    public void getCount() {
        if(count==0){
            System.out.println("已卖完");
            return;
        }
        System.out.println(Thread.currentThread().getName() + "-->售出第:" + (21 - count) + "票");
        count--;
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args){
        JavaStudyThread t1 = new JavaStudyThread();
        Thread thread= new Thread(t1);
        Thread thread1= new Thread(t1);
        thread.start();
        thread1.start();
    }
}
Thread-0-->售出第:1票
Thread-1-->售出第:1票
Thread-1-->售出第:3票
Thread-0-->售出第:3票
Thread-0-->售出第:5票
Thread-1-->售出第:5票
Thread-1-->售出第:7票
Thread-0-->售出第:7票
Thread-1-->售出第:9票
Thread-0-->售出第:9票
Thread-0-->售出第:11票
Thread-1-->售出第:11票
Thread-0-->售出第:13票
Thread-1-->售出第:13票
Thread-0-->售出第:15票
Thread-1-->售出第:15票
Thread-1-->售出第:17票
Thread-0-->售出第:17票
Thread-1-->售出第:19票
Thread-0-->售出第:20票
已卖完
已卖完

从结果可以看出,两个人卖的票存在重复了。票号是唯一,所以这是并发异步带来的问题;

        1-2、处理方法:增加同步关键字 synchronized ,让线程排队,操作共享资源要有先后顺序,一个线程操作完之后,另一个线程才能操作或者读取。

                1-2-1、同步方法:public synchronized void method(int args){执行体…}

  • 防止线程同步访问共享资源造成冲突。
  • 变量需要同步,常量不需要同步(常量存放于方法区)。
  • 多个线程访问共享资源的代码(即线程执行体)有可能是同一份代码,也有可能是不同的代码;无论是否执行同一份代码,只要这些线程的代码访问同一份可变的共享资源,这些线程之间就需要同步。
public class JavaStudyThread implements Runnable{
    private int count = 20;
    public void run() {
        while (true) {
            if (count <= 0) {
                System.out.println("已卖完");
                return;
            }
            getCount();
        }
    }
    public synchronized void getCount() {
        if(count==0){
            System.out.println("已卖完");
            return;
        }
        System.out.println(Thread.currentThread().getName() + "-->售出第:" + (21 - count) + "票");
        count--;
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args){
        JavaStudyThread t1 = new JavaStudyThread();
        Thread thread= new Thread(t1);
        Thread thread1= new Thread(t1);
        thread.start();
        thread1.start();
    }
}
Thread-0-->售出第:1票
Thread-0-->售出第:2票
Thread-1-->售出第:3票
Thread-1-->售出第:4票
Thread-1-->售出第:5票
Thread-0-->售出第:6票
Thread-0-->售出第:7票
Thread-0-->售出第:8票
Thread-1-->售出第:9票
Thread-1-->售出第:10票
Thread-1-->售出第:11票
Thread-1-->售出第:12票
Thread-1-->售出第:13票
Thread-1-->售出第:14票
Thread-0-->售出第:15票
Thread-0-->售出第:16票
Thread-0-->售出第:17票
Thread-1-->售出第:18票
Thread-1-->售出第:19票
Thread-1-->售出第:20票
已卖完
已卖完
已卖完

进程已结束,退出代码0

从结果可以看出:两个人分别各自卖完了手上的票;


                1-2-1、同步代码块:synchronized (Obj){执行体…}

  • Obj称之为同步监视器,可以是任何对象,但是推荐使用共享资源作为同步监视器。
  • 不同方法中无需指定同步监视器,因为同步方法中的同步监视器就是this,就是这个对象本身,或者是class。
public class JavaStudyThread {
    private static String str = "test";

    public void run() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (str) {
                    while (true) {
                        try {
                            System.out.println(str);
                            str.wait();
                            System.out.println(str);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }).start();
    }

    public static void main(String[] args) {
        new JavaStudyThread().run();
        System.out.println("111111");
    }
}

七、死锁问题: 

        1、死锁的原因:

                1-1、多个线程各自占有一个资源的时候,同时等待其他线程占有的资源才能运行。导致这些线程都在等待对方释放资源,都停止了执行。

                1-2、某一个同步代码块同时拥有“两个以上对象的锁”时,就可能发生“死锁”的问题。

class Goddess{}//女神
class GirlFriend{}//女朋友
class Person extends Thread {
    public static Goddess  goddess = new Goddess();
    public static GirlFriend girlFriend = new GirlFriend();
    int choose;
    String personName;

    public Person(int choose, String personName) {
        this.choose = choose;
        this.personName = personName;
    }

    @Override
    public void run() {
        try {
            this.kiss();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //同步代码块中 嵌套了 同步代码块,会导致 线程一致阻塞,大家都在等待对方释放锁,也就停止了执行;
    private void kiss() throws InterruptedException {
        if (choose == 0) {
            synchronized (goddess) {//女神
                System.out.println(personName + "--亲到--女神--被女朋友发现了,女朋友分手了,死锁了");
                Thread.sleep(1000);
                synchronized (girlFriend) {//女朋友
                    System.out.println(personName + "--亲到--女朋友--被女神发现了,女神分手了,死锁了");
                }
            }
        } else {
            synchronized (girlFriend) {
                System.out.println(personName + "--亲到--女朋友--被女神发现了,女朋友分手了,死锁了");
                Thread.sleep(1000);
                synchronized (goddess) {
                    System.out.println(personName + "--亲到--女神--被女朋友发现了,女神分手了,死锁了");
                }
            }
        }
    }
}

public class JavaStudyThread {
    public static void main(String[] args) {
        System.out.println("人生赢家第一条,两女共处渡良宵!");
        System.out.println("两女拿不下,不如回家种地瓜");
        Person person = new Person(0, "穷男A");
        Person person1 = new Person(1, "穷男B");
        person.start();
        person1.start();
    }
}

   输出结果: 说明男主来到后发现女神和女朋友是闺蜜,现场被捉,思索了

人生赢家第一条,两女共处渡良宵!
两女拿不下,不如回家种地瓜
穷男B--亲到--女朋友--被女神发现了,女朋友分手了,死锁了
穷男A--亲到--女神--被女朋友发现了,女朋友分手了,死锁了

    2、解决死锁--synchronized同步锁:

                杜绝synchronized相互嵌套,把方法作为同级使用,如下:

class Goddess{}//女神
class GirlFriend{}//女朋友
class Person extends Thread {
    public static Goddess  goddess = new Goddess();
    public static GirlFriend girlFriend = new GirlFriend();
    int choose;
    String personName;

    public Person(int choose, String personName) {
        this.choose = choose;
        this.personName = personName;
    }

    @Override
    public void run() {
        try {
            this.trueKiss();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //同步代码 移到同级,杜绝相互嵌套,正确的输出结果
    private void trueKiss() throws InterruptedException {
        if (choose == 0) {
            synchronized (girlFriend) {
                System.out.println(personName + "--亲到了--女朋友,--被女神发现了,女神就加入了");
                Thread.sleep(1000);
            }
            synchronized (goddess) {
                System.out.println(personName + "--亲到了--女神,--被女朋友发现了,女朋友就加入了");
            }
        } else {
            synchronized (goddess) {
                System.out.println(personName + "--亲到了--女神,--被女朋友发现了,女朋友就加入了");
                Thread.sleep(1000);
            }
            synchronized (girlFriend) {
                System.out.println(personName + "--亲到了--女朋友,--被女神发现了,女神就加入了");
            }
        }
    }
}

public class JavaStudyThread {
    public static void main(String[] args) {
        System.out.println("人生赢家第一条,两女共处渡良宵!");
        System.out.println("两女拿不下,不如回家种地瓜");
        Person person = new Person(0, "穷男A");
        Person person1 = new Person(1, "穷男B");
        person.start();
        person1.start();
    }
}

    输出结果: 说明男主来到后发现女神和女朋友是闺蜜,分不开各个击破

人生赢家第一条,两女共处渡良宵!
两女拿不下,不如回家种地瓜
穷男A--亲到了--女朋友,--被女神发现了,女神就加入了
穷男B--亲到了--女神,--被女朋友发现了,女朋友就加入了
穷男B--亲到了--女朋友,--被女神发现了,女神就加入了
穷男A--亲到了--女神,--被女朋友发现了,女朋友就加入了

八、Lock(锁):同步锁                

                同步代码块 / 同步⽅法具有的功能 Lock 都有;
                创建对象 Lock lock = new ReentrantLock() ,
                public void lock() :加同步锁
                public void unlock() :释放同步锁

public class JavaStudyThread implements Runnable {

    private static int count =10;

    List<Integer> list = new ArrayList<>();

    private final Lock lock =new ReentrantLock();

    @Override
    public void run() {
        while (true){
            lock.lock();//加锁
            try {
                if(count>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    list.add(count);
                    count--;
                    var aa = list.stream().count();
                    System.out.println(aa);
                }else {
                    break;
                }
            }finally {
                lock.unlock();//解锁
            }
        }
    }

    public static void main(String[] args) {
        JavaStudyThread javaStudyThread=new JavaStudyThread();
        Thread thread=new Thread(javaStudyThread);
        Thread thread2=new Thread(javaStudyThread);
        thread.start();
        thread2.start();
    }

}

 输出结果:按照顺序依次输出结果

1
2
3
4
5
6
7
8
9
10

九、多线程的异步方法:如果存在返回值,则代表有阻塞,那就是同步请求了。无返回值,则代表异步请求,bin

        1、runAsync() 异步无参返回:

        2、supplyAsync() 异步有参返回

        3、allOf() 多个异步处理(针对有参返回)

ublic class JavaStudyThread {

    //runAsync 无参返回   不会阻塞,代表异步
    public void asyncThread() throws Exception {
        CompletableFuture async1 = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName());
                System.out.println("none return Async");
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        // 调用get()将等待异步逻辑处理完成
        async1.get();
    }

    //supplyAsync 有参返回   会阻塞,代表异步
    public void asyncThread2()throws Exception {
        CompletableFuture<String> async2 = CompletableFuture.supplyAsync(() -> {
            return "hello";
        });
        String result = async2.get();
        System.out.println(result);
    }

    //allOf() 多个异步处理(针对有参返回)  会阻塞,代表异步
    public void asyncThread3() throws ExecutionException, InterruptedException {
        CompletableFuture<String> async3 = CompletableFuture.supplyAsync(()->{
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "a";
        });
        CompletableFuture<String> async4 = CompletableFuture.supplyAsync(()->{
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "b";
        });
        CompletableFuture<String> async5 = CompletableFuture.supplyAsync(()->{
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "c";
        });

//        CompletableFuture result = CompletableFuture.allOf(async3,async4,async5);
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String timeValue = sdf.format(date);
        System.out.println(timeValue);
        var a = async3.get();
        var b = async4.get();
        var c = async5.get();
        Date date2 = new Date();
        String timeValue2 = sdf.format(date2);
        System.out.println(a+b+c+";"+timeValue2);

//        var aaa = result.get();
//        String bbb = Stream.of(async3,async4,async5).map(CompletableFuture::join).collect(Collectors.joining(" "));
//        System.out.println(bbb);
    }

    public static void main(String[] args) throws Exception {
        JavaStudyThread javaStudyThread = new JavaStudyThread();
        javaStudyThread.asyncThread3();
    }
}

 4、complete:

CompletableFuture<String> future1 = new CompletableFuture<>();
future.complete("hello world");     //异步线程执行
future.whenComplete((res, throwable) -> {
  System.out.println(res);
});
System.out.println(future1.join());
CompletableFuture<String> future2 = new CompletableFuture<>();
future.completeExceptionally(new Throwable("failed")); //异步线程执行
System.out.println(future2.join());

5、thenApply:

String original = "Message";
CompletableFuture<String> cf = 
 CompletableFuture.completedFuture(original).thenApply(String::toUpperCase);
System.out.println(cf.join());

6、thenCombine:

CompletableFuture<String> cf = 
 CompletableFuture.completedFuture("Message").thenApply(String::toUpperCase);
CompletableFuture<String> cf1 = 
 CompletableFuture.completedFuture("Message").thenApply(String::toLowerCase);
CompletableFuture<String> allCf = cf.thenCombine(cf1, (s1, s2) -> s1 + s2);
System.out.println(allCf.join());

 7、allOf

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Message1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Message2");
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "Message3");
CompletableFuture<String> future = 
 CompletableFuture.allOf(future1, future2, future3).thenApply(v -> {
  String join1 = future1.join();
  String join2 = future2.join();
  String join3 = future3.join();
  return join1 + join2 + join3;});
System.out.println(future.join());

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Tomcat优化及Nginx、tomcat动静分离配置

Tomcat优化及Nginx、tomcat动静分离配置 一、Tomcat优化1、操作系统优化&#xff08;内核参数优化&#xff09;2、Tomacat配置文件优化3、Java虚拟机&#xff08;JVM&#xff09;调优 二、Nginx、tomcat动静分离配置(七层代理)三、四层代理 一、Tomcat优化 Tomcat默认安装下的…

八、进程等待

文章目录 一、进程创建&#xff08;一&#xff09;fork函数概念1.概念2.父子进程共享fork之前和fork之后的所有代码&#xff0c;只不过子进程只能执行fork之后的&#xff01; &#xff08;二&#xff09;fork之后&#xff0c;操作系统做了什么?1.进程具有独立性&#xff0c;代…

(二)CSharp-字段-属性-常量

一、字段 什么是字段 字段&#xff08;filed&#xff09;是一种表示与对象或类型&#xff08;类或结构体&#xff09;关联的变量字段是类型的成员&#xff0c;旧称“成员变量”与对象关联的字段亦称“实例字段”与类型关联的字段称为“静态字段”&#xff0c;由 static 修饰 …

java SSM 学生家长联系系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM学生家长联系系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用…

docker 安装 oracle19c

docker 安装 oracle19c 拉取镜像 sudo docker pull registry.cn-hangzhou.aliyuncs.com/zhuyijun/oracle:19c创建挂载目录 sudo mkdir -p /mydata/oracle/oradata授权 sudo chmod 777 /mydata/oracle/oradata安装 sudo docker run -d \ -p 1521:1521 -p 5500:5500 \ -e ORACLE…

《C++高级编程》读书笔记(三:编码风格)

1、参考引用 C高级编程&#xff08;第4版&#xff0c;C17标准&#xff09;马克葛瑞格尔 2、建议先看《21天学通C》 这本书入门&#xff0c;笔记链接如下 21天学通C读书笔记&#xff08;文章链接汇总&#xff09; 1. 为代码编写文档 在编程环境下&#xff0c;文档通常指源文件中…

Android系统的Ashmem匿名共享内存子系统分析(5)- 实现共享的原理

声明 其实对于Android系统的Ashmem匿名共享内存系统早就有分析的想法&#xff0c;记得2019年6、7月份Mr.Deng离职期间约定一起对其进行研究的&#xff0c;但因为我个人问题没能实施这个计划&#xff0c;留下些许遗憾…文中参考了很多书籍及博客内容&#xff0c;可能涉及的比较…

springboot源码分析-jar启动

概述 Spring Boot 提供了 Maven 插件 spring-boot-maven-plugin&#xff0c;可以方便的将 Spring Boot 项目打成 jar 包或者 war 包。 SpringBoot 是如何通过jar包启动的 java -jar做了什么&#xff1f;看看官网怎么说 If the -jar option is specified, its argument is the …

基础算法(一)——补

快排 归并排序和快速排序的时间复杂度都是 O(nlogn) 左右两边设置哨兵&#xff0c;分成左边小于x, 右边大于x。 &#xff08;先分交换&#xff0c; 再递归&#xff09; #include<iostream> using namespace std; const int N1e610; int n; int q[N]; void quick_sort(i…

【计算机视觉】手把手教你配置stable-diffusion-webui进行AI绘图(保姆级教程)

文章目录 一、前言二、本地化部署的要求三、使用的项目Stable diffusion WebUI项目四、电脑环境配置4.1 安装Anaconda4.2 看版本4.3 配置库包下载环境&#xff0c;加快网络速度4.4 创建环境4.5 激活环境4.6 安装git4.7 安装cuda 五、Stable diffusion环境配置5.1 下载Stable di…

【博学谷学习记录】超强总结,用心分享丨人工智能 LLM langchain初步了解简记

目录 LangChain及必知概念LoadersDocumentText Spltters 文本分割Vectorstores 向量数据库Chain 链Agent 代理Embedding LangChain及必知概念 LangChain 是一个用于开发由语言模型驱动的应用程序的框架。他主要拥有 2 个能力&#xff1a; 可以将 LLM 模型与外部数据源进行连接…

009-从零搭建微服务-系统服务(二)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff08;后端&#xff09;&#xff1a;https://gitee.com/csps/mingyue 源码地址&#xff08;前端&#xff09;&#xff1a;https://gitee.com/csps…

Flowable开始事件-定时开始事件

文章目录 定时开始事件一、定义1. 图形标记2. XML标记2.1、在指定时间点执行2.2、指定定时器之前要等待多长时间&#xff0c; timeDuration可以设置为timerEventDefinition的子元素。2.3、指定重复执行的间隔&#xff0c; 可以用来定期启动流程实例&#xff0c;或为超时时间发送…

NLP的idea,看了就能水一篇论文

1.问题 在中文情感分析任务中,已有方法仅从单极、单尺度来考虑情感特征&#xff0c;无法充分挖掘和利用情感特征信息&#xff0c;模型性能不理想。 单级单尺度&#xff1a;只从一个方面学习文本的特征 多级多尺度&#xff1a;应该是分别从不同方面学习文本的特征&#xff0c…

电脑vcomp140.dll丢失怎么修复

vcomp140.dll是Microsoft的Visual C Redistributable for Visual Studio 2015的一部分。它是一个动态链接库文件&#xff0c;主要用于在Windows操作系统上运行使用Visual Studio 2015编写和编译的软件。与其他许多Windows动态链接库文件类似&#xff0c;vcomp140.dll包含函数和…

(二)CSharp-索引器

1、索引器定义 什么是索引器 索引器&#xff08;indexer&#xff09;是这样一种成员&#xff1a;它使对象能够用与数组相同的方式&#xff08;即使用下标&#xff09;进行索引 索引器的声明参见 C# 语言定义文档注意&#xff1a;没有静态索引器 索引器是一组 get 和 set 访问…

案例32:基于Springboot在线远程考试系统开题报告设计

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

地震勘探基础(十一)之水平叠加处理

水平叠加处理 地震资料经过预处理&#xff0c;静校正&#xff0c;反褶积&#xff0c;速度分析和动校正处理后就要进行水平叠加处理。地震水平叠加处理是地震常规处理的重要环节。 假设一个共中心点道集有三个地震道&#xff0c;经过速度分析和动校正以后&#xff0c;水平叠加…

【PCIE】TLP 发送三阶段和Secondary Bus Reset

TLP传输三阶段 TLP 发送的三个阶段涉及到 PCIe 协议栈中的不同层次&#xff0c;具体如下&#xff1a; TLP 发送阶段 1&#xff08;TS1&#xff09;&#xff1a;这个阶段是在传输层&#xff08;Transaction Layer&#xff09;中进行的。在这个阶段&#xff0c;TLP 数据包会进…

轻松应对大数据挑战!利用ETLCloud实现TDengine数据库的高效查询与数据迁移

TDengine 是一款开源、云原生的时序数据库&#xff0c;专为物联网、工业互联网、金融、IT 运维监控等场景设计并优化。它能让大量设备、数据采集器每天产生的高达 TB 甚至 PB 级的数据得到高效实时的处理&#xff0c;对业务的运行状态进行实时的监测、预警。 根据TDengine文档…