JAVA多线程2_Lock

news2025/8/1 15:11:27

文章目录

  • 一、ReentrantLock类
    • 1.使用ReentrantLock
    • 2.使用ReentrantLock实现多对多
    • 3.公平锁与非公平锁
    • 4.ReentrantLock类其他方法的使用
  • 二、ReentrantReadWriteLock类
    • 1.读读共享
    • 2.写写互斥
    • 3.读写互斥
    • 4.写读互斥
  • 总结

一、ReentrantLock类

1.使用ReentrantLock

  1. 创建reentrantlock.service包,在包下创建MyService类

    package reentrantlock.service;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class MyService {
        private Lock lock =new ReentrantLock();
        public Condition condition = lock.newCondition();
        public void await()
        {
            try {
                lock.lock();
                System.out.println("await时间为"+System.currentTimeMillis());
                condition.await();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally {
                lock.unlock();
            }
        }
        public void signal()
        {
            try{
                lock.lock();
                System.out.println("signal时间为"+System.currentTimeMillis());
                condition.signal();
            }finally {
                lock.unlock();
            }
        }
    }
    

    即使用ReentrantLock的同步锁,并且使用它的Condition对象的一个await/signal方法来实现控制并处理线程的状态,使其进入等待或就绪状态。
    分别用MyService对象的await、signal方法进行实现。

  2. 创建ReentrantLock.thread包,并在包下创建ThreadA类

    package reentrantlock.thread;
    
    import reentrantlock.service.MyService;
    
    public class ThreadA extends Thread{
        private MyService myService;
        public ThreadA(MyService myService)
        {
            this.myService = myService;
        }
    
        @Override
        public void run() {
            myService.await();
        }
    }
    
    

    即ThreadA线程类通过构造方法给MyService对象赋值,并调用该对象的await方法。

  3. 创建reentrantlock.thread包,并在包下创建ThreadB类

    package reentrantlock.thread;
    
    import reentrantlock.service.MyService;
    
    public class ThreadB extends Thread{
        private MyService myService;
        public ThreadB(MyService myService)
        {
            this.myService = myService;
        }
    
        @Override
        public void run() {
            myService.signal();
        }
    }
    

    即ThreadB线程类通过构造方法给MyService对象赋值,并调用该对象的signal方法。

  4. 创建reentrantlock.test包,并在包下创建Run类

    package reentrantlock.test;
    
    import reentrantlock.service.MyService;
    import reentrantlock.thread.ThreadA;
    import reentrantlock.thread.ThreadB;
    
    public class Run {
        public static void main(String[] args) throws InterruptedException {
            MyService myService =new MyService();
            ThreadA threadA = new ThreadA(myService);
            threadA.start();
            Thread.sleep(3000);
            ThreadB threadB = new ThreadB(myService);
            threadB.start();
        }
    }
    
    

    即通过ThreadA 调用MyService 的await方法,主线程休眠3秒后,ThreadB 调用MyService 的signal方法。

  5. await()方法通过调用Unsafe.park方法使线程暂停运行。
    如果传入true,则第二个参数单位时间为毫秒,此时第二个单位时间为绝对时间

    //获取Unsafe类的theUnsafe属性
    Field f = Unsafe.class.getDeclaredField("theUnsafe");
    //给theUnsafe设置为可使用
    f.setAccessible(true);
    Unsafe unsafe = (Unsafe) f.get(null);
    System.out.println("begin"+System.currentTimeMillis());
    unsafe.park(true,System.currentTimeMillis()+3000);
    System.out.println("end"+System.currentTimeMillis());
    

    如果传入false,则第二个参数单位时间为纳秒,此时为相对时间

    //获取Unsafe类的theUnsafe属性
    Field f = Unsafe.class.getDeclaredField("theUnsafe");
    //给theUnsafe设置为可使用
    f.setAccessible(true);
    Unsafe unsafe = (Unsafe) f.get(null);
    System.out.println("begin"+System.currentTimeMillis());
    unsafe.park(false,3000000000L);
    System.out.println("end"+System.currentTimeMillis());
    
  6. signal()方法通过调用Unsafe.unpark方法唤醒线程。

    package reentrantlock.thread;
    
    import sun.misc.Unsafe;
    
    public class MyThread extends Thread{
        private Unsafe unsafe;
        private Thread mainThread;
        public MyThread(Unsafe unsafe, Thread mainThread) {
            this.unsafe = unsafe;
            this.mainThread = mainThread;
        }
    
        @Override
        public void run() {
            try {
                Thread.sleep(6000);
                unsafe.unpark(mainThread);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
    
    
    package reentrantlock.test;
    
    import reentrantlock.thread.MyThread;
    import sun.misc.Unsafe;
    
    import java.lang.reflect.Field;
    
    public class Test2 {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InterruptedException {
            //获取Unsafe类的theUnsafe属性
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            //给theUnsafe设置为可使用
            f.setAccessible(true);
            Unsafe unsafe = (Unsafe) f.get(null);
            MyThread myThread = new MyThread(unsafe, Thread.currentThread());
            //MyThread线程启动休眠6s,再调用unpark方法
            myThread.start();
            //main线程休眠0.2秒
            Thread.sleep(200);
            //开始打印时间为myThread休眠的200毫秒后,所以从begin到end的时间未5.8秒。
            System.out.println("begin"+System.currentTimeMillis());
            unsafe.park(false,0L);
            System.out.println("end"+System.currentTimeMillis());
        }
    }
    
    

2.使用ReentrantLock实现多对多

  1. 创建reentrantlock.service包,然后创建MyService3类

    package reentrantlock.service;
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class MyService3 {
        private Lock lock =new ReentrantLock();
        public Condition condition = lock.newCondition();
        private boolean hasValue = false;
        public void set()
        {
            try {
                lock.lock();
                while(hasValue==true)
                {
                    condition.await();
                }
                System.out.println("生产");
                hasValue=true;
                condition.signalAll();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally {
                lock.unlock();
            }
    
        }
        public void get()
        {
            try{
                lock.lock();
                while(hasValue==false)
                {
                    condition.await();
                }
                System.out.println("消费");
                hasValue=false;
                condition.signalAll();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally {
                lock.unlock();
            }
        }
    }
    
    

    即跟之前的wait/notifyAll机制的多对多一样,而ReentrantLock的多对多实现也是使用While来判断条件,使用Condition对象的signalAll方法来唤醒所有等待线程

  2. 创建reentrantlock.thread包,然后创建ThreadA3类

    package reentrantlock.thread;
    
    import reentrantlock.service.MyService3;
    
    public class ThreadA3 extends Thread{
        private MyService3 myService;
        public ThreadA3(MyService3 myService)
        {
            this.myService = myService;
        }
    
        @Override
        public void run() {
            myService.set();
        }
    }
    
    
  3. 创建reentrantlock.thread包,然后创建ThreadB3类

    package reentrantlock.thread;
    
    import reentrantlock.service.MyService3;
    
    public class ThreadB3 extends Thread{
        private MyService3 myService;
        public ThreadB3(MyService3 myService)
        {
            this.myService = myService;
        }
    
        @Override
        public void run() {
            myService.get();
        }
    }
    
    
    
  4. 创建reentrantlock.test包,然后创建Run3类

    package reentrantlock.test;
    
    import reentrantlock.service.MyService3;
    import reentrantlock.thread.ThreadA3;
    import reentrantlock.thread.ThreadB3;
    
    public class Run3 {
        public static void main(String[] args) {
            MyService3 service = new MyService3();
            ThreadA3[] A = new ThreadA3[10];
            ThreadB3[] B = new ThreadB3[10];
            for (int i = 0; i < 10; i++) {
                A[i] = new ThreadA3(service);
                B[i] = new ThreadB3(service);
                A[i].start();
                B[i].start();
            }
        }
    }
    
    

    即分别创建10个ThreadA3和ThreadB3实例分别调用MyService3实例中的set和get方法。set则是生产操作,get则是消费操作。从而实现多对多。

3.公平锁与非公平锁

  1. 创建reentrantlock.service包,在包下创建MyService4 类

    package reentrantlock.service;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class MyService4 {
        public Lock lock;
        public MyService4(boolean fair)
        {
            lock = new ReentrantLock(fair);
        }
        public void testMethod()
        {
            try {
                lock.lock();
                System.out.println("testMethod"+Thread.currentThread().getName());
                //此处的10ms用于配合 array2有更多可能在非公平的情况下找到锁
                //如果线程数量够多,也可以不休眠或让休眠时间更小
                Thread.sleep(10);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally{
                lock.unlock();
            }
    
        }
    }
    
    

    即通过MyService4的构造方法给ReentrantLock传参,生成非公平锁对象。
    休眠是为了让其他线程有机会抢到锁对象。

  2. 创建reentrantlock.thread包,在包下创建MyThread2 类

    package reentrantlock.thread;
    
    import reentrantlock.service.MyService4;
    
    public class MyThread2 extends Thread{
        private MyService4 service4;
        public MyThread2(MyService4 service4)
        {
            super();
            this.service4 = service4;
        }
    
        @Override
        public void run() {
            service4.testMethod();
        }
    }
    
    

    即线程类用来调用MyService4的testMethod方法。

  3. 创建reentrantlock.test包,在包下创建Run4类

    package reentrantlock.test;
    
    import reentrantlock.service.MyService4;
    import reentrantlock.thread.MyThread2;
    
    public class Run4 {
        public static void main(String[] args) throws InterruptedException {
            //即通过MyService4的构造方法将bool值传入,再给ReentrantLock传入,生成非公平锁NonfairSync。
            MyService4 myService4 = new MyService4(false);
            MyThread2[] array1 = new MyThread2[1000];
            MyThread2[] array2 = new MyThread2[1000];
            long begin = System.currentTimeMillis();
            for (int i = 0; i < array1.length; i++) {
                array1[i]= new MyThread2(myService4);
                array1[i].setName("array1+++"+(i+1));
                array1[i].start();
            }
            Thread.sleep(10);
            for (int i = 0; i < array2.length; i++) {
                array2[i]= new MyThread2(myService4);
                array2[i].setName("array2---"+(i+1));
                array2[i].start();
            }
            
        }
    }
    
    

即通过MyService4的构造方法生成一个非公平锁,生成两个线程数组,使用for循环去启动线程,线程组1和线程组2中间的休眠是为了让线程组1先排队,而线程执行期间休眠是为了让线程组2可以在线程运行时,线程组1刚刚释放锁,线程组二有机会可以抢到线程组1刚刚释放的锁,如果线程量够大,线程执行时的休眠可以不要。
非公平锁运行结果:
在这里插入图片描述
而公平锁就是将MyService4构造方法传入的值修改为true,它是按申请锁资源的顺序来给锁资源的。
即上述结果中2不会在1之前。

4.ReentrantLock类其他方法的使用

  1. public int getHoldCount()方法,作用是查询"当前线程"保持此锁的个数,也就是调用lock方法的次数。
    执行lock方法进行锁重入,导致count+1,而unlock方法导致count-1。

  2. public final int getQueueLength方法,作用是返回正等待获取此锁的线程的估计数。

  3. public int getWaitQueueLength(Condition condition)方法,作用是返回等待此锁相关的给定条件Condition的线程估计数。即返回调用过condition.await方法的线程估计数。

  4. public final boolean hasQueuedThread(Thread thread),作用是查询指定的线程是否正在等待获取此锁,即判断参数中的线程是否在等待队列中。

  5. public final boolean hasQueuedThreads(),作用是查询是否有线程正在等待获取此锁,即等待队列中是否有等待的线程。

  6. public boolean hasWaiters(Condition condition),作用是查询是否有线程正在等待与此锁有关的condition对象,即是否有线程执行了condition对象的await方法而呈等待状态。

  7. public final boolean isFair(),作用是判断是不是公平锁。
    ReentrantLock默认是非公平锁。

  8. public boolean isHeldByCurrentThread(),作用是查询当前线程是否持有此锁。

  9. public boolean isLocked(),作用是查询此锁是否有线程持有,并且未释放。

  10. public void lockInterruptibly(),作用是当某个线程尝试获得锁并且阻塞在lockInterruptibly()方法时,该线程可以被中断。
    即使用lockInterruptibly方法进行加锁时,该锁可以被中断(interrupt)。

  11. public boolean tryLock(),作用是当前线程发现锁被其他线程持有了,则返回false,那么程序继续执行后面的代码,而不是呈阻塞等待锁状态的。
    即可以将tryLock作为一个判断条件,true(获得锁)则执行true指定的语句,false执行false指定的语句。

  12. public boolean tryLock(long timeout,TimeUnit unit),如果在指定的timeout时间内持有了锁,则返回true,如果超过时间则返回false。

  13. public boolean await(long time,TimeUnit unit)和public final native void wait(long timeout)方法一样,具有自动唤醒功能。

  14. public long awaitNanos(long nanosTimeout),具有自动唤醒功能,时间单位是纳秒。
    1000纳秒=1微秒,1000微秒=1毫秒,1000毫秒=1秒。

  15. public boolean awaitUntil(Date deadline),作用是在指定的日期结束等待。
    13-15的方法都是具有自动唤醒功能的等待方法。

  16. public void awaitUninterruptibly(),作用是等待的过程中,不允许被中断。即将await方法换成awaitUninterruptibly方法。

二、ReentrantReadWriteLock类

使用ReentrantLock对象时,对所有的操作都同步,包括读取操作,这样会耗费大量时间,降低运行效率。

1.读读共享

  1. 创建一个reentrantreadwritelock.service包,在包下创建MyService 类

    package reentrantreadwritelock.service;
    
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class MyService {
        private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        private String username = "abc";
        public void testMethod()
        {
            try {
                lock.readLock().lock();
                System.out.println("begin "+Thread.currentThread().getName()+ System.currentTimeMillis());
                System.out.println("print service"+ username);
                Thread.sleep(4000);
                System.out.println("end "+Thread.currentThread().getName()+""+System.currentTimeMillis());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally {
                lock.readLock().unlock();
            }
        }
    }
    
    
  2. 创建一个reentrantreadwritelock.thread包,在包下创建ThreadA类

    package reentrantreadwritelock.thread;
    
    import reentrantreadwritelock.service.MyService;
    
    public class ThreadA extends Thread{
        private MyService myService = new MyService();
        public ThreadA(MyService myService)
        {
            this.myService = myService;
        }
    
        @Override
        public void run() {
            myService.testMethod();
        }
    }
    
    
  3. 创建一个reentrantreadwritelock.thread包,在包下创建ThreadB类

    package reentrantreadwritelock.thread;
    
    import reentrantreadwritelock.service.MyService;
    
    public class ThreadB extends Thread{
        private MyService myService = new MyService();
        public ThreadB(MyService myService)
        {
            this.myService = myService;
        }
    
        @Override
        public void run() {
            myService.testMethod();
        }
    }
    
    
  4. 创建一个reentrantreadwritelock.thread包,在包下创建ThreadB类

    package reentrantreadwritelock.test;
    
    import reentrantreadwritelock.service.MyService;
    import reentrantreadwritelock.thread.ThreadA;
    import reentrantreadwritelock.thread.ThreadB;
    
    public class Run {
        public static void main(String[] args) {
            MyService myService =new MyService();
            ThreadA a = new ThreadA(myService);
            a.setName("a");
            a.start();
            ThreadB b = new ThreadB(myService);
            b.setName("b");
            b.start();
        }
    }
    
    

    即创建一个MyService 实例,将其传入ThreadA和ThreadB实例中,两个线程共用一把锁。读锁是共享锁,所以两个读操作不会互斥,可以同时进行读操作,减少同步耗费的时间。

2.写写互斥

  1. 创建一个reentrantreadwritelock.service包,在包下创建MyService2 类

    package reentrantreadwritelock.service;
    
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class MyService2 {
        private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        private String username = "abc";
        public void write()
        {
            try {
                lock.writeLock().lock();
                System.out.println("获得写锁 "+Thread.currentThread().getName()+ System.currentTimeMillis());
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally {
                lock.writeLock().unlock();
            }
        }
    }
    
    
  2. 创建一个reentrantreadwritelock.thread包,在包下创建ThreadA2 类

    package reentrantreadwritelock.thread;
    
    
    import reentrantreadwritelock.service.MyService2;
    
    public class ThreadA2 extends Thread{
        private MyService2 myService = new MyService2();
        public ThreadA2(MyService2 myService)
        {
            this.myService = myService;
        }
    
        @Override
        public void run() {
            myService.write();
        }
    }
    
    
  3. 创建一个reentrantreadwritelock.thread包,在包下创建ThreadB2 类

    package reentrantreadwritelock.thread;
    
    import reentrantreadwritelock.service.MyService2;
    
    public class ThreadB2 extends Thread{
        private MyService2 myService = new MyService2();
        public ThreadB2(MyService2 myService)
        {
            this.myService = myService;
        }
    
        @Override
        public void run() {
            myService.write();
        }
    }
    
    
  4. 创建一个reentrantreadwritelock.test包,在包下创建Run2 类

    package reentrantreadwritelock.test;
    
    import reentrantreadwritelock.service.MyService2;
    import reentrantreadwritelock.thread.ThreadA2;
    import reentrantreadwritelock.thread.ThreadB2;
    
    public class Run2 {
        public static void main(String[] args) {
            MyService2 myService =new MyService2();
            ThreadA2 a = new ThreadA2(myService);
            a.setName("a");
            a.start();
            ThreadB2 b = new ThreadB2(myService);
            b.setName("b");
            b.start();
        }
    }
    
    

    即创建一个MyService2实例,2个线程传入同一个MyService2实例,线程调用MyService2同一个方法,该方法使用写锁,此时写写互斥,需要等第一个线程执行方法结束后,第二个线程才能执行方法内的任务。

3.读写互斥

  1. 创建一个reentrantreadwritelock.service包,在包下创建MyService3 类

    package reentrantreadwritelock.service;
    
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class MyService3 {
        private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        public void read()
        {
            try {
                lock.readLock().lock();
                System.out.println("获得读锁"+Thread.currentThread().getName()+System.currentTimeMillis());
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally {
                lock.readLock().unlock();
            }
        }
        public void write()
        {
            try {
                lock.writeLock().lock();
                System.out.println("获得写锁"+Thread.currentThread().getName()+System.currentTimeMillis());
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }finally {
                lock.writeLock().unlock();
            }
        }
    }
    
    
  2. 创建一个reentrantreadwritelock.thread包,在包下创建ThreadA3 类

    package reentrantreadwritelock.thread;
    
    
    import reentrantreadwritelock.service.MyService3;
    
    public class ThreadA3 extends Thread{
        private MyService3 myService = new MyService3();
        public ThreadA3(MyService3 myService)
        {
            this.myService = myService;
        }
    
        @Override
        public void run() {
            myService.read();
        }
    }
    
    
  3. 创建一个reentrantreadwritelock.thread包,在包下创建ThreadB3 类

    package reentrantreadwritelock.thread;
    
    import reentrantreadwritelock.service.MyService3;
    
    public class ThreadB3 extends Thread{
        private MyService3 myService = new MyService3();
        public ThreadB3(MyService3 myService)
        {
            this.myService = myService;
        }
    
        @Override
        public void run() {
            myService.write();
        }
    }
    
    
  4. 创建一个reentrantreadwritelock.test包,在包下创建Run3 类

    package reentrantreadwritelock.test;
    
    import reentrantreadwritelock.service.MyService3;
    import reentrantreadwritelock.thread.ThreadA3;
    import reentrantreadwritelock.thread.ThreadB3;
    
    public class Run3 {
        public static void main(String[] args) {
            MyService3 myService =new MyService3();
            ThreadA3 a = new ThreadA3(myService);
            a.setName("a");
            a.start();
            ThreadB3 b = new ThreadB3(myService);
            b.setName("b");
            b.start();
        }
    }
    
    

    即创建一个MyService3实例,2个线程传入同一个MyService3实例,线程A调用MyService3的read方法,线程B调用MyService3的write方法,此时读写互斥,需要等第一个线程执行读方法结束后,第二个线程才能执行写方法内的任务。

4.写读互斥

即跟读写互斥相同,线程AB调用的方法互换即可。

总结

  1. 使用Condition对象,Condition对象是跟ReentrantLock对象绑定的。Condition有await和signal、signalAll方法,通过awiat方法使线程进入等待状态,signal唤醒线程,signalAll唤醒全部线程。
  2. 通知部分线程时,可以使用创建多个Condition实例,通过调用指定的Condition对象的signal/signalAll方法唤醒指定部分的线程。
  3. 实现生产/消费模式多对多时,需要使用while来判断,并且唤醒方法用signalAll,还有就是用多个线程实例来操作这个生产和消费的方法。生产和消费的方法使用同步锁lock。
  4. 公平锁采用先到先得的策略,每次获取锁之前都会检查队列有没有排队等待的线程,没有才会尝试获取锁,如果有就将当前线程追加到队列中。
    非公平锁,采用“有机会插队”的策略,一个线程获取锁之前,要先尝试获取锁,而不是在队列中等待;如果获取锁没有成功,那么将自身追加到队列中进行等待。即比公平锁多了一个线程未入队时的尝试获取锁操作(插队操作)。
    公平锁在进入方法后,就会申请锁资源,查看等待队列中是否有线程等待,有则加入该等待队列,没有则获取锁资源。
  5. ReentrantLock具有完全互斥排他的特点,同一时间只有一个县城在执行ReentrantLock.lock()方法后面的任务,保证了同时写实例变量的线程安全性,但效率非常低下。
    ReentrantReadWriteLock读写锁,可以在同时进行读操作时不需要同步执行,提升了运行速度,加快运行效率。
    ReentrantLock和ReentrantReadWriteLock之间没有继承关系。
    读写锁表示有2个锁,一个是读操作相关的锁,也叫共享锁,另一个是写操作相关的锁,也叫排它锁。读锁之间不互斥,读锁和写锁与写锁和写锁之间互斥。即出现写锁就出现互斥同步的效果。
  6. Lock对象比synchronized关键具有更多更细的方法,Lock对象是synchronized关键字的进阶。
    并发包中,大量的的类使用了Lock接口作为同步的处理方式。

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

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

相关文章

【计算机毕业设计】36.网易购商城购物平台源码

一、系统截图&#xff08;需要演示视频可以私聊 摘 要 本毕业设计的内容是设计并且实现一个基于JSP技术的网易购购物平台。它是在Windows下&#xff0c;以MYSQL为数据库开发平台&#xff0c;Tomcat网络信息服务作为应用服务器。网易购购物平台的功能已基本实现&#xff0c;主…

sqli-labs/Less-62

欢迎界面提示我们一共由130次机会 而且还是以id作为注入点 每次重置都会随机分配表名、字段名、表格数据 首先判断注入类型 输入id1 and 12 回显如下 说明不属于数字型 接着输入1 回显如下 没有回显 说明注入点带有单引号 佐证一下吧 输入1-- 回显如下 说明不是纯粹的单引号…

【Redis技术探索】「高可用架构模式」哨兵(sentinel)模式实现主从故障互切换模式详解

哨兵&#xff08;sentinel&#xff09;模式实现主从故障互切换模式详解Redis的多种模式Redis单机模式Redis单机模式的优点Redis单机模式的缺点Redis主从复制旧版本配置新版本配置查看主节点信息主从模式的优点主从复制的弊端Redis哨兵模式分析哨兵结构组成哨兵模式的主从切换Re…

ROS-TCP-Connector and ROS-TCP-Endpoint

Unity官方提供了和ROS交互的接口&#xff1a;ROS-TCP-Connector and ROS-TCP-Endpoint。有了这两个Unity就能够更好的和真实机器人做交互。两个接口的实现基于ROS#、ros_bridge&#xff0c;所以基本上以后用这个就可以了。 源码如下&#xff1a;   ROS-TCP-Endpoint&#xff…

学生党蓝牙耳机怎么选?四款性价比高的蓝牙耳机推荐

随着时代的发展&#xff0c;人们越来越追求事物的使用体验感。便捷的蓝牙耳机成为更多人的选择&#xff0c;对于学生党来说&#xff0c;蓝牙耳机的重要性不言而喻。接下来&#xff0c;我来推荐几款适合学生党的蓝牙耳机。 1、南卡小音舱蓝牙耳机 综合得分&#xff1a;96分(满…

骨传导耳机伤耳朵吗?带你一分钟了解骨传导耳机

最近听到最多的一句话就是&#xff1a;骨传导耳机伤耳朵吗&#xff1f;骨传导耳机不会伤害耳朵&#xff0c;反而更能保护耳朵。骨传导耳机是不入耳的&#xff0c;既不伤耳&#xff0c;还能保护耳部。骨传导耳机我用过很多款&#xff0c;知道有哪些骨传导耳机是比较好的&#xf…

产品公开后就不能再申请专利了吗?

问题一&#xff1a;申请专利会导致产品技术泄密吗&#xff1f; 很多人担心申请专利后会导致自己的专利技术公之于众&#xff0c;会让同行模仿生产。其实&#xff0c;我们不妨反向思考一下&#xff0c;假如我们没有申请专利&#xff0c;我们销售生产出去的产品就不容易被模仿吗…

华为机试 - TLV解析Ⅰ

目录 题目描述 输入描述 输出描述 用例 题目解析 算法源码 题目描述 TLV编码是按[Tag Length Value]格式进行编码的&#xff0c;一段码流中的信元用Tag标识&#xff0c;Tag在码流中唯一不重复&#xff0c;Length表示信元Value的长度&#xff0c;Value表示信元的值。 码…

【Canvas】JavaScript用Canvas制作美丽的对称图案

生活中有看到一个对称图案&#xff0c;看着很美&#xff0c;于是想到&#xff0c;试试用Canvas试着画对称图形来&#xff0c;想到就做&#xff0c;自己还真捣鼓出来了&#xff0c;自己弄了好多的对称图这里就不晒出来了&#xff0c;接下来讲讲怎么做&#xff0c;有兴趣的同学可…

java 自定义生成验证码

目录说明效果展示Base64编码的文件类型枚举类验证码默认常量值验证码生成工具类使用说明 项目登录或者其他重要的操作中都要生成验证码&#xff0c;其重要性在此不多说。 主要是介绍自己封装的验证码生成工具类的使用。 建议安装lombok插件,不使用此插件则需要手动生成get、s…

cron表达式,结构、字段说明、特殊字符说明、常用表达式

1.cron表达式的结构 Cron表达式是一个字符串&#xff0c;结构非常简单。Cron表达式从左到右分为6或7个字段&#xff0c;每个字段代表一个含义&#xff0c;用空格隔开。如下图所示&#xff1a; 2.cron表达式中各个字段的说明和规则 Cron一共有7位&#xff0c;最后一位是年份&…

浅析资源调度框架YARN

第一章 资源调度框架YARN理论 1.1 YARN概述 分布式操作系统 hadoop 1.xMapReduce主从架构 主节点JobTracker 从节点TaskTrackerslot hadoop 2.xMapReduce编程API YARN主从架构 主节点ResourceManager 从节点NodeManagerContainer hadoop 3.xCommonHDFS 纠删码 …

关于升级高德地图导航9.5.0的问题 ‘com.amap.api:navi-3dmap:9.5.0_3dmap9.5.0‘

最近打开项目&#xff0c;发现高德有新版本更新&#xff0c;果断更新。哈哈哈哈。然而结果好像并没有这么简单。要是世界上什么事情这么简单就好了。年轻人。还是太年轻了啊。 然后更新完最新的依赖 /*高德地图远程依赖*/implementation com.amap.api:navi-3dmap:9.5.0_3dmap9…

I/O 设备(输入/输出设备)

文章目录I/O 设备输入设备输出设备1&#xff0c;显示器2&#xff0c;打印机3&#xff0c;投影仪I/O 设备 输入设备 借助计算机的输入设备&#xff0c;用户能够轻松地将数据或者指令传递给计算机。同时&#xff0c;计算机中的 CPU 会接收用户输入的指令或数据&#xff0c;并对…

Tesla M40 下Ubuntu anaconda pycharm pytorch安装

显卡&#xff1a;Tesla M40 24GB (2张&#xff09; 显卡驱动版本(推荐)&#xff1a;470.57.02 cuda版本&#xff1a;11.4 安装前需要&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;禁用nouveau驱动&#xff01;&#xff01;&#xff01;&#xff01;&#x…

矢量网络分析仪的S11和S12参数是什么呢?

矢量网络分析仪的基础功能是S参数测试。所谓S参数&#xff0c;就是散射参数&#xff0c;是描述电磁波在被测设备的入射波量、反射波量以及波量传输特性的参数。简单理解&#xff1a;S11代表端口1的反射&#xff0c;S22代表端口2的反射&#xff0c;S21是端口1至端口2的传输&…

阿里云安装软件:jdk11

命令下载 1. 安装准备 检查系统jdk版本 java -version检查jdk自带安装包 rpm -qa | grep java卸载jdk yum -y remove tzdata-java.noarch如果有就卸载&#xff0c;卸载的包名通过&#xff08;rpm -qa | grep java&#xff09;获取&#xff0c;包名要全部输入 rpm -e --nodeps …

Kotlin基础认知 - 为何Kotlin文件有的带.kt后缀,有的不带?

有一天看到项目中的Kotlin类&#xff0c;有的有.kt后缀&#xff0c;有的没有&#xff0c;针对这个情况我就简单看了下&#xff0c;然后记录一波 创建 Kotlin Class 或 Kotlin File创建Kotlin class创建Kotlin File俩者区别展现形式外部展现内部展现延伸扩展、对向转换Class无后…

【Silvaco example】Temperature Ramping - Effect on Leakage

1、例子讲解 本示例演示了Atlas中任何device的全局温度梯度&#xff08;global temperature ramping&#xff09;的正确方法。 &#xff08;1&#xff09;结构定义 为了简单起见&#xff0c;这里选择了二极管结构。 go atlasmeshx.mesh loc0.00 spac0.05 x.mesh loc0.10 sp…

简单手段发IF=7+文章:磷酸三苯酯对鲤鱼的毒性作用及肠道微生物群落影响

研究背景 磷酸三苯基酯&#xff08;TPHP&#xff09;是一种有机磷阻燃剂&#xff0c;它通过挥发以及溶解分散到环境中&#xff0c;并通过食物链富集生物体&#xff0c;对生态系统产生不可避免的负面影响。已发现TPHP可以引起组织病变&#xff0c;干扰脂质代谢&#xff0c;并降…