多线程与高并发(三)

news2024/11/17 0:05:05

【 day3课前复习 】:

【AtomicInteger】:

原子性——都是用CAS机制来实现。

【 expected , update 】:

//有时候也会写三个值——你要修改的那个对象。
expected——期望值。(旧值)
update——更新值。(新值)

【 LongAdder 】:

//很多线程对一个数进行递增这件事,在实际工作中经常的会碰到。——《秒杀案例》

【三种方式效率比较】:

    static long count2 = 0L;
    static AtomicLong count1 = new AtomicLong(0L);
    static LongAdder count3 = new LongAdder();

【比较代码】:

package Ten_Class.t03.no131;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;

public class T02_AtomicVsSyncVsLongAdder {
    private static final int THREAD_COUNT = 50;
    private static final int LOOPS_COUNT = 100_0000;

    static long count2 = 0L;
    static AtomicLong count1 = new AtomicLong(0L);
    static LongAdder count3 = new LongAdder();

    public static void main(String[] args) throws Exception {
        Thread[] threads = new Thread[THREAD_COUNT];

        for (int i = 0; i < threads.length; i++) {
            threads[i] =
                    new Thread(() -> {
                        for (int k = 0; k < LOOPS_COUNT; k++) count1.incrementAndGet();
                    });
        }

        long start = System.currentTimeMillis();

        for (Thread t : threads) t.start();

        for (Thread t : threads) t.join();

        long end = System.currentTimeMillis();

        //TimeUnit.SECONDS.sleep(10);

        System.out.println("Atomic: " + count1.get() + " time " + (end - start));
        //-----------------------------------------------------------
        Object lock = new Object();

        for (int i = 0; i < threads.length; i++) {
            threads[i] =
                    new Thread(new Runnable() {
                        @Override
                        public void run() {

                            for (int k = 0; k < LOOPS_COUNT; k++)
                                synchronized (lock) {
                                    count2++;
                                }
                        }
                    });
        }

        start = System.currentTimeMillis();

        for (Thread t : threads) t.start();

        for (Thread t : threads) t.join();

        end = System.currentTimeMillis();


        System.out.println("Sync: " + count2 + " time " + (end - start));


        //----------------------------------
        for (int i = 0; i < threads.length; i++) {
            threads[i] =
                    new Thread(() -> {
                        for (int k = 0; k < LOOPS_COUNT; k++) count3.increment();
                    });
        }

        start = System.currentTimeMillis();

        for (Thread t : threads) t.start();

        for (Thread t : threads) t.join();

        end = System.currentTimeMillis();

        //TimeUnit.SECONDS.sleep(10);

        System.out.println("LongAdder: " + count1.longValue() + " time " + (end - start));

    }

    static void microSleep(int m) {
        try {
            TimeUnit.MICROSECONDS.sleep(m);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

【最终输出】:
在这里插入图片描述

【LongAdder为何效率高呢?】:

其内部做了类似于分段锁的概念。
//在内部的时候会把这个值放到数组里。
在这里插入图片描述
每250个线程锁在一个区域里 ,最后进行一个大汇总。线程数特别多的情况下LongAdder是有优势的。

【 间歇性复习 】:

【atomicXXX】:

CAS

【increment】:

  • sync
  • atomicXXX
  • LongAdder

【 ReentrantLock 】:

//基于CAS操作的锁;

[ synchronized ]:

synchronized必须是可重入的,否则子类调用父类是无法实现的。
【test0】:

package Ten_Class.t03.no133;

import java.util.concurrent.TimeUnit;

public class T00_ReentrantLock1 {
    synchronized void m1() {
        for (int i = 0; i < 10; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);
        }
    }

    synchronized void m2() {
        System.out.println("m2 ...");
    }

    public static void main(String[] args) {
        T00_ReentrantLock1 rl = new T00_ReentrantLock1();
        new Thread(rl::m1).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(rl::m2).start();
    }
}

【最终输出】:
在这里插入图片描述

【test1】:

package Ten_Class.t03.no133;

import java.util.concurrent.TimeUnit;

public class T01_ReentrantLock1 {
    synchronized void m1() {
        for (int i = 0; i < 10; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);
            if (i == 2) m2();
        }

    }

    synchronized void m2() {
        System.out.println("m2 ...");
    }

    public static void main(String[] args) {
        T01_ReentrantLock1 rl = new T01_ReentrantLock1();
        new Thread(rl::m1).start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

【最终输出】:
在这里插入图片描述

【总结】:

上面的实验说明了sync锁是可重入的,sync是可以调sync方法的。

【替代sync】:

ReentrantLock是可以替代synchronized的。
在这里插入图片描述
synchronized是自动解锁的,只要sync后面的大括号执行完了这个锁就自动结束了。但是Lock必须得手动解锁。解锁语句一定要写在finally里面一定要保证最后解锁。

【 ReentrantLock的优点 】:

ReentrantLock有一些功能还是要比Synchronized要强大的。
使用synchronized如果锁不定,就会进入阻塞/等待状态,但是如果使用ReentrantLock我们自己就可以决定是否要去 wait 。

【实验测试】:

【没拿到】:

package Ten_Class.t03.no133;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class T03_ReentrantLock3_没拿到 {
	Lock lock = new ReentrantLock();

	void m1() {
		try {
			lock.lock();
			for (int i = 0; i < 10; i++) {
				TimeUnit.SECONDS.sleep(1);

				System.out.println(i);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	/**
	 * 使用tryLock进行尝试锁定,不管锁定与否,方法都将继续执行;
	 * 可以根据tryLock的返回值来判定是否锁定;
	 * 也可以指定tryLock的时间 ,由于tryLock(time)抛出异常,所以要注意unclock�Ĵ�������ŵ�finally��
	 */
	void m2() {
		/*
		boolean locked = lock.tryLock();
		System.out.println("m2 ..." + locked);
		if(locked) lock.unlock();
		*/

		boolean locked = false;

		try {
			locked = lock.tryLock(5, TimeUnit.SECONDS);
			System.out.println("m2 ..." + locked);
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			if (locked) lock.unlock();
		}

	}

	public static void main(String[] args) {
		T03_ReentrantLock3_没拿到 rl = new T03_ReentrantLock3_没拿到();
		new Thread(rl::m1).start();
		try {
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		new Thread(rl::m2).start();
	}
}

【拿到了】:

//只修改一处即可

			for (int i = 0; i < 3; i++) {
				TimeUnit.SECONDS.sleep(1);

				System.out.println(i);
			}

【lockInterruptibly】:

/**
 * 使用ReentrantLock还可以调用lockInterruptibly方法,可以对线程interrupt方法
 * 在一个线程等待锁的过程中,可以被打断。
 */
package Ten_Class.t03.no133;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class T04_ReentrantLock4 {

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();


        Thread t1 = new Thread(() -> {
            try {
                lock.lock();
                System.out.println("t1 start");
                TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
                System.out.println("t1 end");
            } catch (InterruptedException e) {
                System.out.println("interrupted!");
            } finally {
                lock.unlock();
            }
        });
        t1.start();

        Thread t2 = new Thread(() -> {
            try {
                //lock.lock();   //放开这个,注掉下面的,这样t2线程就无法被打断了。
                lock.lockInterruptibly();
                    //可以对interrupt()方法做出响应。————我在lock的时候可以响应被别人打断( 你打断我,我是可以做出响应的 )。
                //synchronized一旦 wait 了之后 , 你一定得让别人notify~~~ , 你才能够醒来 。

                System.out.println("t2 start");
                TimeUnit.SECONDS.sleep(5);
                System.out.println("t2 end");
            } catch (InterruptedException e) {
                System.out.println("interrupted!");
            } finally {
                lock.unlock();
            }
        });
        t2.start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t2.interrupt(); //打断线程2的等待。
    }
}

【公平锁的关键】:

在这里插入图片描述
//一个新线程过来抢锁,会不会先检查队列里的内容是公平锁的关键。
【代码中的公平锁】:
private static ReentrantLock lock = new ReentrantLock(true); //参数为true表示为公平锁,ReentrantLock默认其实是非公平锁。
//公平锁的意思就是谁等在前面就先让谁执行,而不是说谁后来了马上就执行。

package Ten_Class.t03.no133;

import java.util.concurrent.locks.ReentrantLock;

public class T05_ReentrantLock5 extends Thread {

    private static ReentrantLock lock = new ReentrantLock(true); //参数为true表示为公平锁,
    //公平锁的意思就是谁等在前面就先让谁执行,而不是说谁后来了马上就执行。

    public void run() {
        for (int i = 0; i < 10; i++) {
            lock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "获得锁");
            } finally {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        T05_ReentrantLock5 rl = new T05_ReentrantLock5();
        Thread th1 = new Thread(rl);
        Thread th2 = new Thread(rl);
        th1.start();
        th2.start();
    }
}

【 ReentrantLock VS synchronized 】:

  1. : RL是可以代替synchronized的;
    2) :
    cas VS sync
    tryLock
    lockinterupptibly
    公平和非公平的切换

【 CountDownLatch 】:

//倒数的门栓,倒数的数字到了,54321,门栓就开了。

 package Ten_Class.t03.no134;

import java.util.concurrent.CountDownLatch;

public class T06_TestCountDownLatch {
    public static void main(String[] args) {
        usingJoin();
        usingCountDownLatch();
    }

    private static void usingCountDownLatch() {
        Thread[] threads = new Thread[100];

        CountDownLatch latch = new CountDownLatch(threads.length);  //门栓上面记着数字————100。

        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                int result = 0;
                for (int j = 0; j < 10000; j++) result += j;

                latch.countDown();  //门栓上记录的数字减一。减到0的时候下面的栓才会往前走。
            });
        }

        for (int i = 0; i < threads.length; i++) {
            threads[i].start();
        }

        try {
            latch.await();   //门栓在这里给我拴住门。————等待线程的结束。
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

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

    private static void usingJoin() {
        Thread[] threads = new Thread[100];

        for (int i = 0; i < threads.length; i++) {
            threads[i] = new Thread(() -> {
                int result = 0;
                for (int j = 0; j < 10000; j++) result += j;
            });
        }

        for (int i = 0; i < threads.length; i++) {
            threads[i].start();
        }

        for (int i = 0; i < threads.length; i++) {
            try {
                threads[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

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

//    @Test
    public void testCountDown() {
        CountDownLatch latch = new CountDownLatch(3);

        System.out.println(latch.getCount());
        latch.countDown();
        System.out.println(latch.getCount());
        latch.countDown();
        System.out.println(latch.getCount());
        latch.countDown();
        System.out.println(latch.getCount());
        latch.countDown();
        System.out.println(latch.getCount());
    }
}

【 CyclicBarrier 】:

//循环栅栏 , 满了之后就推倒;

【构造器】:

【一参】:
数字——达到的数量。
【二参】:
new Runnable(){ }

【示例程序(只有一参) 】:

package Ten_Class.t03.no135;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class T07_FirstTest {

    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(20);

        
        for (int i = 0; i < 100; i++) {

            new Thread(() -> {
                try {
                    barrier.await();    //这里等够20个线程了,就会开始发车。

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

【示例程序(两个参数)】:

package Ten_Class.t03.no135;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class T07_TestCyclicBarrier {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(20, () -> System.out.println("满人"));

        for (int i = 0; i < 100; i++) {

            new Thread(() -> {
                try {
                    barrier.await();
                    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();

        }
    }
}

【Phaser 】:

//用于遗传算法。

package Ten_Class.t03.no136;

import java.util.Random;
import java.util.concurrent.Phaser;
import java.util.concurrent.TimeUnit;

public class T09_TestPhaser2 {
    static Random r = new Random();
    static MarriagePhaser phaser = new MarriagePhaser();


    static void milliSleep(int milli) {
        try {
            TimeUnit.MILLISECONDS.sleep(milli);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        phaser.bulkRegister(7);

        for (int i = 0; i < 5; i++) {

            new Thread(new Person("p" + i)).start();
        }

        new Thread(new Person("新郎")).start();
        new Thread(new Person("新娘")).start();

    }


    static class MarriagePhaser extends Phaser {
        @Override
        protected boolean onAdvance(int phase, int registeredParties) {

            switch (phase) {
                case 0:
                    System.out.println("所有人都到齐了!" + registeredParties);
                    System.out.println();
                    return false;
                case 1:
                    System.out.println("所有人都吃完了!" + registeredParties);
                    System.out.println();
                    return false;
                case 2:
                    System.out.println("所有人都离开了!" + registeredParties);
                    System.out.println();
                    return false;
                case 3:
                    System.out.println("婚礼结束!新郎新娘抱抱!" + registeredParties);
                    return true;
                default:
                    return true;
            }
        }
    }


    static class Person implements Runnable {
        String name;

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

        public void arrive() {

            milliSleep(r.nextInt(1000));
            System.out.printf("%s 到达现场!\n", name);
            phaser.arriveAndAwaitAdvance();
        }

        public void eat() {
            milliSleep(r.nextInt(1000));
            System.out.printf("%s 吃完!\n", name);
            phaser.arriveAndAwaitAdvance();
        }

        public void leave() {
            milliSleep(r.nextInt(1000));
            System.out.printf("%s 离开!\n", name);


            phaser.arriveAndAwaitAdvance();
        }

        private void hug() {
            if (name.equals("新郎") || name.equals("新娘")) {
                milliSleep(r.nextInt(1000));
                System.out.printf("%s 洞房!\n", name);
                phaser.arriveAndAwaitAdvance();
            } else {
                phaser.arriveAndDeregister();
                //phaser.register()
            }
        }

        @Override
        public void run() {
            arrive();


            eat();


            leave();


            hug();
        }
    }
}

在这里插入图片描述

【 ReadWriteLock 】:

  • 共享锁
  • 排它锁

【 Semaphore 】:

//信号灯——信号灯亮的时候能够执行,不亮的话不能执行。
在这里插入图片描述
//构造器里写的是1 , 所以只能允许一个线程同时运行,acquire方法调用一次,最大允许数量就会减少一个。
【总结】:
我最多允许多少个线程同时运行 —— 限流。

【程序测试】:

package Ten_Class.t03.no138;

import java.util.concurrent.Semaphore;

public class T11_TestSemaphore {
    public static void main(String[] args) {
        //Semaphore s = new Semaphore(2);
        Semaphore s = new Semaphore(2, true);  //默认非公平 , 传true代表公平 。
        //允许一个线程同时执行
//        Semaphore s = new Semaphore(1);

        new Thread(() -> {
            try {
                s.acquire();  //阻塞方法。

                System.out.println("T1 running...");
                Thread.sleep(200);
                System.out.println("T1 running...");

            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                s.release();
            }
        }).start();

        new Thread(() -> {
            try {
                s.acquire();

                System.out.println("T2 running...");
                Thread.sleep(200);
                System.out.println("T2 running...");

                s.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

在这里插入图片描述

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

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

相关文章

LeetCode刷题复盘笔记—一文搞懂动态规划之剑指 Offer 46. 把数字翻译成字符串问题(动态规划系列第三十四篇)

今日主要总结一下动态规划的一道题目&#xff0c;剑指 Offer 46. 把数字翻译成字符串 题目&#xff1a;剑指 Offer 46. 把数字翻译成字符串 Leetcode题目地址 题目描述&#xff1a; 给定一个数字&#xff0c;我们按照如下规则把它翻译为字符串&#xff1a;0 翻译成 “a” &am…

小型云台机械手的制作

1. 运动功能说明 小型云台机械手&#xff0c;下方的云台可以提供左右旋转和上下摆动的动作&#xff0c;与舵机夹爪配合可以完成简单的抓取和搬运。 2.结构说明 该样机由一个 R207小型舵机云台 上串联了一个 舵机夹爪模组 构成。 3. 运动功能实现 3.1 电子硬件 在这个示例中&a…

Redis集群系列五 —— 分区/片概念

什么是分区 分区就是将所存储的数据按照一定的规则存储在不同的存储服务或介质上&#xff0c;通过降低单服务或介质的数据量级来提升数据处理能力&#xff0c;从而达到拥有数据处理横向扩容的能力的目的。 还可简单的理解为分区就是将数据拆分到多个 Redis 实例的过程&#xf…

21. 合并两个有序链表播报文章

题目描述 这是一道难度为简单的题目&#xff0c;同时&#xff0c;这道题也是Leetcode148题中&#xff0c;链表归并排序中重要的组成部分。 题目描述 题目分析 本题的题目简单易懂&#xff0c;输入为两个有序链表&#xff0c;要求将链表合并为一个有序的链表。在此不在再赘述…

【消息中间件】RocketMQ如何实现Producer的负载均衡

目录 一、前言 二、实现Producer的负载均衡 1、负载均衡选取一条消息队列并且高可用 1.1、模拟随机递增取模消息队列数为5 1.2、模拟随机递增取模消息队列数为6 1.3、判断Broker代理是否可用 2、更新故障项维护startTimestamp字段 2.1、退避运算 2.2、更新故障项维护st…

干货 | 数字经济创新创业——数字经济下的商业模式与解决方案

下文整理自清华大学大数据能力提升项目能力提升模块课程“Innovation & Entrepreneurship for Digital Economy”&#xff08;数字经济创新创业课程)的精彩内容。主讲嘉宾&#xff1a;Kris Singh: CEO at SRII, Palo Alto, CaliforniaVisiting Professor of Tsinghua Unive…

卷积、转置卷积、膨胀卷积学习记录

Conv计算&#xff1a; 计算公示 1、pytorch中默认参数&#xff0c;以conv1d为例 torch.nn.Conv1d(in_channels, out_channels, kernel_size, stride1, padding0, dilation1, groups1, biasTrue, padding_mode‘zeros’, deviceNone, dtypeNone&#xff09; 2、输出卷积尺寸&am…

MySQL常见内置函数及其使用

目录 1、聚合函数 2、日期函数 3、字符串函数 4、数学函数 5、其它函数 1、聚合函数 函数说明 COUNT([DISTINCT] expr) 返回查询到的数据的 数量SUM([DISTINCT] expr)返回查询到的数据的 总和&#xff0c;不是数字没有意义AVG([DISTINCT] expr)返回查询到的数据的 平均值…

数据蛙恢复软件替代产品有哪些?15款顶尖数据恢复软件清单

数据蛙恢复软件是一款国内数据恢复软件&#xff0c;可以在很多品牌的电脑上使用。但是你可能会遇到数据蛙恢复软件扫描不到需要恢复文件的情况。那么有没有更专业的数据恢复软件可以找到更多误删数据&#xff1f;本文将为你介绍最值的推荐的15个数据蛙恢复软件替代产品。 丢失…

Web兼容性测试的要点

对于网页的兼容性我们主要考虑的是各种浏览器对前台页面的兼容性&#xff0c;因为浏览器对页面的影响是最大的。 现在浏览器的种类越来越多&#xff0c;网页中展现出来的内容也越来越丰富&#xff0c;这些内容包括网页中的字体、图片、动画等&#xff0c;而且有些内容需要网页…

AlexNet学习笔记(2)

里面 有些东西 对于现在来说都是错误的 而且由大量的细节对于现在来说没有必要 而且是过度的enginnering 一篇论文的第一段通常是讲一则故事 我们在做什么研究 哪个方向 有什么东西然后为什么很重要 正则化 regularization好像没有那么重要&#xff0c;并不是最关键的 最关键…

前端监控系统的搭建

UI自动化测试库 puppeteer&#xff1a;https://zhuanlan.zhihu.com/p/524254998 - google出品 cypress - 据说比puppeteer好用 前端监控体系 性能监控 异常监控 行为监控&#xff1a;埋点体系 主动监控 被动监控 前端性能数据捕获&#xff1a; 打点方式&#xff0c;结…

pyqt5 QPainter绘制图形,并旋转

PyQt5 的绘图系统使用户可以在屏幕或打印设备上用相同的 API 绘图&#xff0c;QPainter 是用来进行 绘图操作的类&#xff0c;一般的绘图设备包括 QWidget、QPixmap、QImage 等&#xff0c;这些绘图设备为 QPainter 提供了一个“画布” QWidget 类是所有界面组件的基类&#xf…

【细节注入模型】

Detail-Injection-Model-Inspired Deep Fusion Network for Pansharpening &#xff08;细节注入模型启发的深度融合网络全色锐化算法&#xff09; 全色锐化是一种图像融合方法&#xff0c;其目的是将低空间分辨率的多光谱&#xff08;MS&#xff09;图像与高空间分辨率的全色…

FFmpeg学习笔记--FFplay简单过滤器、FFmpeg命令参数

目录 1--FFplay简单过滤器 2--FFmpeg命令参数 2-1 主要参数 2-1-1 -i设定输入流 2-1-2 -f设定输出格式 2-1-3 -ss设定开始时间 2-1-4 -t设定时间长度 2-1-5 代码实例 2-2 音频参数 2-2-1 -aframes设置输出的音频帧数 2-2-2 -b:a设置音频码率 2-2-3 -ar设置音频采样…

SVG 安全

一 任务目标 本篇文章的目的有&#xff1a;[ ] 了解 SVG 漏洞[ ] 了解 SVG 常见防护手段[ ] 搜寻 SVG 数据安全性校验和过滤的库[ ] 了解如何使用此类库来进行 SVG 上传防护[ ] 阅读源码&#xff0c;能明确讲述此类库做了什么如果对你有所帮助&#xff0c;不妨点赞、评论、收藏…

Windows系统安装Git教程

今天给大家介绍Windows系统安装Git命令。 一、Git版本控制工具简介 git是一个开源的分布式版本控制系统。所谓版本控制系统&#xff0c;是开发者最重要的工具之一&#xff0c;可以有效的解决版本的同步以及不同开发者之家的通信问题&#xff0c;提升协同开发的效率。版本控制…

JAVA数据类型及转换

一、数据类型 数据类型字节数byte字节型占用1个字节取值范围&#xff1a;-27 ~ 27-1-128~127short短整型占用2个字节取值范围&#xff1a;-215 ~ 215-1-32768~32767&#xff0c;在实际开发中使用较少int整型占用4个字节取值范围&#xff1a;-231 ~ 231-1-2147483648-214748364…

大道至简:数据库的终极未来

墨天轮2022年12月份的报告已经出炉&#xff0c;这一期的主题是&#xff1a;大道至简&#xff0c;自治为王。在公众号回复&#xff1a;下载 可以获得各期报告下载链接。数据库的终极未来是什么&#xff1f;这是行业里一直在探讨的命题&#xff0c;复杂但是也简单。大道至简01Or…

硬盘无法格式化怎么解决?数据丢失怎么恢复?

有时遇到一些特殊情况&#xff0c;需要我们对电脑磁盘进行格式化。但是硬盘无法格式化&#xff0c;这时我们应该怎么进行操作&#xff1f;你可以根据下面的操作&#xff0c;通过磁盘的创建权限&#xff0c;或者通过磁盘管理来进行格式化&#xff0c;一起来看看下面的简单操作&a…