在项目中学习到的东西

本文介绍了当Git账号过期时如何通过命令行进行克隆,并探讨了Java中Thread.join()方法的作用,说明了其在单线程和多线程场景下的应用。同时,详细解析了CountDownLatch的概念和使用,通过实例展示了如何在多线程间协调执行。最后比较了CountDownLatch与Thread.join()的区别,强调了CountDownLatch在复杂线程控制中的灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、当git的账号过期的时候,通过git bash是导出不了的 ,但是通过以下命令就可以了

 git clone -b dev1.10.2【分支名】 http://caoyuewx【用户名】:1995830Cy【密码】@10.148.68.13/walle/c_server.git

在这里插入图片描述
2、Thead.join()的作用

第一种:单线程+主线程    
     Thread中,join()方法的作用是调用线程等待该线程完成后,才能继续用下运行。
public static void main(String[] args) throws InterruptedException
    {
        System.out.println("main start");

        Thread t1 = new Thread(new Worker("thread-1"));
        t1.start();
        t1.join();
        System.out.println("main end");
    }
    在上面的例子中,main线程要等到t1线程运行结束后,才会输出“main end”。如果不加t1.join(),main线程和t1线程是并行的。而加上t1.join(),程序就变成是顺序执行了。

第二种:多线程+主线程
    我们在用到join()的时候,通常都是main线程等到其他多个线程执行完毕后再继续执行。其他多个线程之间并不需要互相等待。
    下面这段代码并没有实现让其他线程并发执行,线程是顺序执行的。
public static void main(String[] args) throws InterruptedException
    {
        System.out.println("main start");

        Thread t1 = new Thread(new Worker("thread-1"));
        Thread t2 = new Thread(new Worker("thread-2"));
        t1.start();
        //等待t1结束,这时候t2线程并未启动
        t1.join();
        
        //t1结束后,启动t2线程
        t2.start();
        //等待t2结束
        t2.join();

        System.out.println("main end");
    }
    为了让t1、t2线程并行,我们可以稍微改一下代码,下面给出完整的代码:
public class JoinTest
{

    public static void main(String[] args) throws InterruptedException
    {
        System.out.println("main start");

        Thread t1 = new Thread(new Worker("thread-1"));
        Thread t2 = new Thread(new Worker("thread-2"));
        
        t1.start();
        t2.start();
        
        t1.join();
        t2.join();

        System.out.println("main end");
    }
}

class Worker implements Runnable
{

    private String name;

    public Worker(String name)
    {
        this.name = name;
    }

    @Override
    public void run()
    {
        for (int i = 0; i < 10; i++)
        {
            try
            {
                Thread.sleep(1l);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            System.out.println(name);
        }
    }

}
    上面就是t1,t2是并行执行,t1、t2两个执行完毕之后,才会执行主线程

3、countDownLatch的理解与使用

  CountDownLatch是什么?
       CountDownLatch是具有synchronized机制的一个工具,目的是让一个或者多个线程等待,直到其他线程的一系列操作完成。
       CountDownLatch初始化的时候,需要提供一个整形数字,数字代表着线程需要调用countDown()方法的次数,当计数为0时,线程才会继续执行await()方法后的其他内容。CountDownLatch(int count)

  对象中的方法
       getCount: 返回当前的计数count值,
       public void await() throws InterruptedException 调用CountDownLatch对象的await方法后。 会让当前线程阻塞,直到计数count递减至0。
       public void countDown()    调用此方法后,会减少计数count的值。递减后如果为0,则会释放所有等待的线程,表示让调用await方法的地方能够往下执行   
	   其中:
		  await还提供了一个带参数和返回值的方法: public boolean await(long timeout, TimeUnit unit)  throws InterruptedException
		  表示:如果计数count正常递减,返回0后,await方法会返回true并继续执行后续逻辑。 或是,尚未递减到0,而到达了指定的时间间隔后,方法返回false。 如果时间小于等于0,则此方法不执行等待。
  实际案例:与Thead.join做对比,join方法表示只有改线程执行完毕之后才可以执行
public class Worker1 implements Runnable {
    @Override
    public void run() {
        System.out.println("-线程1启动");
        try {
            Thread.sleep(13_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程1完成--我休眠13秒\r\n");
    }
}

public class Worker2 implements Runnable {
    @Override
    public void run() {
        System.out.println("-线程2启动");
        try {
            Thread.sleep(3_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程2完成--我休眠3秒\r\n");
    }
}

public class Worker3 implements Runnable {
    @Override
    public void run() {
        System.out.println("-线程3启动");
        try {
            Thread.sleep(3_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        try {
            Thread.sleep(3_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程3完成--我休眠6秒\r\n");
        System.out.println();
    }
}


public class Main {
    public static void main(String[] args) throws InterruptedException {
        Worker1 worker1 = new Worker1();
        Worker2 worker2 = new Worker2();
        Worker3 worker3 = new Worker3();

        Thread thread1 = new Thread(worker1,"线程1");
        Thread thread2 = new Thread(worker2,"线程2");
        Thread thread3 = new Thread(worker3,"线程3");

        thread1.start();
        thread2.start();
        thread3.start();

        thread1.join();
        thread2.join();
        thread3.join();
        System.out.println("主线程结束....");

    }
}
	   打印结果如下:
         -线程3启动
         -线程2启动
         -线程1启动
         线程2完成--我休眠3秒
         线程3完成--我休眠6秒
         线程1完成--我休眠13秒
         主线程结束....
         Process finished with exit code 0
	   
	  可以看出三个线程是并行执行的。启动顺序,并不和执行完毕的顺序一致,但可以明确的是,主线程为一直阻塞,直到三个线程执行完毕。
public class CountDownArticle {
    /**
     * 模拟 主线程 依赖 线程A初始化一个数据,才能继续加载后续逻辑
     */
    public static void main(String[] args) throws InterruptedException {
        AtomicReference<String> key = new AtomicReference<>("");
        CountDownLatch countDownLatch = new CountDownLatch(3);
            Thread t = new Thread(() -> {
            try {

                //休眠5秒,模拟数据的初始化
                TimeUnit.SECONDS.sleep(5);

                key.set("核心秘钥123456");
                System.out.println("数据1初始化完毕");

                //释放---此处可以在任何位置调用,很灵活
                countDownLatch.countDown();

                System.out.println("数据2初始化完毕");
                countDownLatch.countDown();

                System.out.println("数据3初始化完毕");
                countDownLatch.countDown();

            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });
        t.start();

        //等待数据初始化,阻塞
        countDownLatch.await();
        System.out.println("key:" + key.get());
    }
}
	   打印内容如下:
        数据1初始化完毕
        数据2初始化完毕
        数据3初始化完毕
        key:核心秘钥123456


  CountDownLatch和Join用法的区别?
        在使用join()中,多个线程只有在执行完毕之后才能被解除阻塞,
        而在CountDownLatch中,线程可以在任何时候任何位置调用countdown方法减少计数,通过这种方式,
        我们可以更好地控制线程的解除阻塞,而不是仅仅依赖于连接线程的完成。
        如果仅仅只需要等待线程的执行完毕,那么join可能就能满足。但是如果需要灵活的控制线程,使用CountDownLatch。
    
  注意事项 
        countDownLatch.countDown(); 这一句话尽量写在finally中,或是保证此行代码前的逻辑正常运行,因为在一些情况下,出现异常会导致无法减1,然后出现死锁。 CountDownLatch 是一次性使用的,当计数值在构造函数中初始化后,就不能再对其设置任何值,当 CountDownLatch 使用完毕,也不能再次被使用 
  
  原理: 从源码可以看出,CountDownLatch是依赖于 AbstractQueuedSynchronizer来实现这一系列逻辑的。 

在这里插入图片描述

      队列同步器AbstractQueuedSynchronizer 是一个用来构建锁和同步器的框架,它在内部定义了一个被标识为volatile的名为state的变量,用来表示同步状态。多个线程之间可以通过AQS来独占式或共享式的抢占资源。 并且它通过内置的FIFO队列来完成线程的排队工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值