Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >JUC同步锁

JUC同步锁

原创
作者头像
程序员NEO
发布于 2023-09-30 11:50:30
发布于 2023-09-30 11:50:30
2540
举报

ReentrantLock

ReentrantLock 是什么

java 除了使用关键字 synchronized 外,还可以使用 ReentrantLock 实现独占锁的功能。

ReentrantLock 相比 synchronized 而言功能更加丰富,使用起来更为灵活,也更适合复杂的并发场景。

ReentrantLock 与 Synchronzied 对比

都是独占锁

  • synchronized 是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。
  • ReentrantLock 也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。

都是可重入锁

  • synchronized 可重入锁,因为加锁和解锁自动进行,不必担心最后是否释放锁。
  • ReentrantLock 也可重入锁,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。

是否响应中断

  • synchronized 不可响应中断,一个线程获取不到锁就一直等着。
  • ReentrantLock 可以响应中断。

ReentrantLock 独有的

  • ReentrantLock 还可以实现公平锁机制。
  • 在锁上等待时间最长的线程将获得锁的使用权。
  • 通俗的理解就是谁排队时间最长谁先执行获取锁。

接下来来看看几个 ReentrantLock 的示例如下

可重入锁使用 synchronized 实现

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class ReentrantLock01 {
    synchronized void method1() {
        for (int i = 0; i < 10; i++) {
            SleepTools.sleepSecond(1);
            System.out.println(i);
            
            // 在一个锁当中调用了另一个带有锁的方法
            if (i == 2) {
                methods2();
            }
        }
    }

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

    public static void main(String[] args) {
        ReentrantLock01 rl = new ReentrantLock01();
        new Thread(rl::method1).start();
    }
}

使用 Reentrantlock 完成可重入锁

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class ReentrantLock02 {
    Lock lock = new ReentrantLock();

    void method1() {
        try {
            // synchronized(this)
            lock.lock();

            for (int i = 0; i < 10; i++) {
                SleepTools.sleepSecond(1);
                System.out.println(i);
            }
        } finally {

            // lock必须手动释放锁,在finally中进行锁的释放
            lock.unlock();
        }
    }

    void methods2() {
        try {
            lock.lock();
            System.out.println("methods2 start...");
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ReentrantLock02 rl = new ReentrantLock02();
        new Thread(rl::method1).start();
        new Thread(rl::methods2).start();
    }
}

tryLock 进行尝试锁

tryLock 进行尝试锁定,不管锁定与否,方法都将继续执行,根据 tryLock 的返回值来判定是否锁定

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class ReentrantLock03 {
    Lock lock = new ReentrantLock();

    void method1() {
        try {
            // synchronized(this)
            lock.lock();
            for (int i = 0; i < 3; i++) {
                SleepTools.sleepSecond(1);
                System.out.println(i);
            }
        } finally {
            // lock必须手动释放锁,在finally中进行锁的释放
            lock.unlock();
        }
    }

    void methods2() {
        boolean locked = lock.tryLock();

        System.out.println("method start ..." + locked);

        if (locked) {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ReentrantLock03 rl = new ReentrantLock03();
        new Thread(rl::method1).start();
        new Thread(rl::methods2).start();
    }
}
代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class ReentrantLock04 {
    Lock lock = new ReentrantLock();

    void method1() {
        try {
            // synchronized(this)
            lock.lock();

            for (int i = 0; i < 6; i++) {
                SleepTools.sleepSecond(1);
                System.out.println(i);
            }
        } finally {
            // lock必须手动释放锁,在finally中进行锁的释放
            lock.unlock();
        }
    }

    void methods2() {
        boolean locked = false;
        try {
            // 等待5秒 如果锁还没有释放 就结束 不再等待 如果释放 继续加锁处理
            locked = lock.tryLock(5, TimeUnit.SECONDS);

            System.out.println("method2 start ..." + locked);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (locked) {
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        ReentrantLock04 rl = new ReentrantLock04();
        new Thread(rl::method1).start();
        new Thread(rl::methods2).start();
    }
}

线程打断

synchronized 没有办法打断线程

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 **/
public class ReentrantLock05 {
    public static void main(String[] args) {

        Thread t1 = new Thread(() -> {
            synchronized (ReentrantLock05.class) {
                System.out.println("thread1 start");
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread1 end");
            }
        });
        t1.start();

        Thread t2 = new Thread(() -> {
            synchronized (ReentrantLock05.class) {
                System.out.println("thread2 start");
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread2 end");
            }
        });
        t2.start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 打断线程2的等待
        t2.interrupt();
    }
}

lock 打断线程等待

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 **/
public class ReentrantLock06 {
    public static void main(String[] args) {
        Lock lock = new ReentrantLock();

        Thread t1 = new Thread(() -> {
            try {
                lock.lock();

                System.out.println("thread1 start");
                TimeUnit.SECONDS.sleep(5);
                System.out.println("thread1 end");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });
        t1.start();

        Thread t2 = new Thread(() -> {
            try {
                // lock.lock() 调用此方法不会打断线程
                // 调用lockInterruptibly会打断线程等
                lock.lockInterruptibly();

                System.out.println("thread2 start");
                TimeUnit.SECONDS.sleep(2);
                System.out.println("thread2 end");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });
        t2.start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 打断线程2的等待
        t2.interrupt();
    }
}

公平锁

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class ReentrantLock07 extends Thread {
    /**
     * 参数为true表示为公平锁
     */
    private static final ReentrantLock LOCK = new ReentrantLock(true);

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            LOCK.lock();

            try {
                System.out.println(Thread.currentThread().getName() + "获得锁");
            } finally {
                LOCK.unlock();
            }
        }
    }

    public static void main(String[] args) {
        ReentrantLock07 rl = new ReentrantLock07();

        Thread thread1 = new Thread(rl);
        Thread thread2 = new Thread(rl);
        thread1.start();
        thread2.start();
    }
}

CountDownLatch

CountDownLatch 类的作用

CountDownLatch 能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行 使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一 CountDownLatch 是一个同步工具类 当计数器的值为 0 时,表示所有的线程都已经完成一些任务,然后在 CountDownLatch 上等待的线程就可以恢复执行接下来的任务

CountDownLatch 的用法

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class CountDownLatch01 {
    public static void main(String[] args) {
        // 线程池当中创建三个线程
        ExecutorService service = Executors.newFixedThreadPool(3);

        final CountDownLatch latch = new CountDownLatch(3);

        for (int i = 0; i < 3; i++) {
            Runnable runnable = () -> {
                System.out.println("子线程" + Thread.currentThread().getName() + "开始执行");
                System.out.println("子线程" + Thread.currentThread().getName() + "执行完成");

                // 当前线程调用此方法,则计数器减一
                latch.countDown();
            };

            service.execute(runnable);
        }

        try {
            System.out.println("主线程" + Thread.currentThread().getName() + "等待子线程执行完成...");

            // 阻塞当前线程,直到计数器的值为 0
            latch.await();

            System.out.println("主线程" + Thread.currentThread().getName() + "开始执行...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

如上是一个小案例,接下来来看看一个需求:百米赛跑,4 名运动员选手到达场地等待裁判口令,裁判一声口令,选手听到后同时起跑,当所有选手到达终点,裁判进行汇总排名,如下就是代码实现。

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 **/
public class CountDownLatch02 {
    public static void main(String[] args) {
        // 创建线程池
        ExecutorService service = Executors.newCachedThreadPool();

        final CountDownLatch cpOrder = new CountDownLatch(1);

        final CountDownLatch personAnswer = new CountDownLatch(4);

        for (int i = 0; i < 4; i++) {
            Runnable runnable = () -> {
                try {
                    System.out.println("选手" + Thread.currentThread().getName() + "运行员等待枪响...");

                    cpOrder.await();

                    System.out.println("选手" + Thread.currentThread().getName() + "听到指令,开始跑");

                    Thread.sleep((long)(Math.random() * 10000));

                    System.out.println("选手" + Thread.currentThread().getName() + "到达终点");

                    personAnswer.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            };
            service.execute(runnable);
        }

        try {
            // 所有线程就绪
            SleepTools.sleepSecond(2);

            for (int i = 3; i > 0; i--) {
                System.out.println(i);
                SleepTools.sleepSecond(1);
            }

            System.out.println("裁判开枪   " + Thread.currentThread().getName() + "彭~~~~~");

            cpOrder.countDown();

            System.out.println("裁判" + Thread.currentThread().getName() + "已开枪,等待所有选手到达终点");

            // 终点等待 第一个线程中有countDown方法 四个执行完countDown=0 继续执行后续代码
            personAnswer.await();

            System.out.println("所有选手都到达终点");

            System.out.println("裁判" + Thread.currentThread().getName() + "汇总成绩排名");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        service.shutdown();
    }
}

CyclicBarrier

CyclicBarrier 是什么

CyclicBarrier 中文意思是 “循环栅栏”java.util.concurrent 包下面的多线程工具类。

它的作用就是会让所有线程都等待完成后才会继续下一步行动。

CyclicBarrier 的基本使用

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 **/
public class CountDownLatch03 {
    public static void main(String[] args) {
        // 1.会议需要三个人
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {

            // 2、这是三个人都到齐之后会执行的代码
            System.out.println("三个人都已到达会议室");
        });

        // 3、定义三个线程,相当于三个参会的人
        for (int i = 0; i < 3; i++) {
            SleepTools.sleepSecond(1);

            new Thread(() -> {
                SleepTools.sleepSecond(1);
                System.out.println("第" + Thread.currentThread().getName() + "个人到达会议室");
                try {

                    // 5、等待其他人到会议室
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }

                System.out.println(Thread.currentThread().getName() + "开始开会");
            }).start();
        }
    }
}

CountDownLatch 和 CyclicBarrier 的区别

Phaser

Phaser 概述

Phaser 是 JDK7 新增的一个同步辅助类,在功能上跟 CyclicBarrier 和 CountDownLatch 差不多。

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class PhaserTest {
    private final static Random RANDOM = new Random();

    static class Task extends Thread {
        private final Phaser phaser;

        Task(Phaser phaser) {
            this.phaser = phaser;
            this.start();
        }

        @Override
        public void run() {
            SleepTools.sleepSecond(RANDOM.nextInt(3));

            System.out.println("线程:" + this.getName() + "完成阶段1");

            // 等待所有线程全部执行完阶段 1 之后才会进入下一个阶段
            phaser.arriveAndAwaitAdvance();

            SleepTools.sleepSecond(RANDOM.nextInt(5));
            System.out.println("线程:" + this.getName() + "完成阶段2");

            phaser.arriveAndAwaitAdvance();
            System.out.println("线程:" + this.getName() + "完成阶段3");

            phaser.arriveAndAwaitAdvance();
            System.out.println("线程:" + this.getName() + "完成");
        }
    }

    public static void main(String[] args) {
        // 参数为参于者,写几, 就要有几个参与线程,如果多的话, 会一直处理阻塞状态
        Phaser phaser = new Phaser(5);

        for (int i = 0; i < 5; i++) {
            new Task(phaser);
        }
    }
}
代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class PhaserTest1 {
    public static void main(String[] args) {
        // 参数为参于者,写几, 就要有几个参与线程,如果多的话, 会一直处理阻塞状态
        WorkPhase phaser = new WorkPhase(3, 5);

        for (int i = 0; i < 5; i++) {
            new PhaserTest.Task(phaser);
        }
    }
}

class WorkPhase extends Phaser {
    private final int totalPhase;

    WorkPhase(int totalPhase, int parties) {
        super(parties);
        this.totalPhase = totalPhase;
    }

    @Override
    protected boolean onAdvance(int phase, int registeredParties) {
        System.out.println(phase + "期工程完工验收,共" + registeredParties + "期");

        // 返回true 后续的就不会再执行, 返回false后续的内容会继续执行
        return totalPhase == phase || registeredParties == 0;
    }
}

ReadWriteLock

ReadWriteLock 概述

ReadWriteLock 是一个接口 ReadWriteLock 管理一组锁,一个是只读的锁,一个是写锁 Java 并发库中 ReetrantReadWriteLock 实现了 ReadWriteLock 接口并添加了可重入锁的特性

ReadLock

读锁。加了读锁的资源, 可以在没有写锁的时候被多个线程共享

如果 t1 线程已经获取了读锁,那么此时存在以下状态:

(1) 如果 t2 线程要申请写锁,则 t2 会一直等待 t1 释放读锁

(2) 如果 t2 线程要申请读锁,则 t2 可以直接访问读锁,也就是说 t1 和 t2 可以共享资源,就和没加锁的效果一样

WriteLock

写锁,是独占锁。加了写锁的资源,不能再被其他线程读或写 如果 t1 已经获取了写锁,那么此时无论线程 t2 要申请写锁还是读锁,都必须等待 t1 释放写锁

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class ReadWriteLock1 {
    static Lock lock = new ReentrantLock();
    private static int value;

    public void read(Lock lock) {
        lock.lock();
        SleepTools.sleepSecond(1);
        System.out.println("读完");
        lock.unlock();
    }

    public void write(Lock lock, int v) {
        lock.lock();
        SleepTools.sleepSecond(1);
        value = v;
        System.out.println("写完");
        lock.unlock();
    }

    public static void main(String[] args) {
        ReadWriteLock1 wrl = new ReadWriteLock1();

        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                wrl.read(lock);
            }).start();
        }

        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                wrl.write(lock, new Random().nextInt());
            }).start();
        }
    }
}
代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class ReadWriteLock2 {
    /**
     * 共享锁与排它锁
     */
    static ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    static Lock readLock = readWriteLock.readLock();

    static Lock writeLock = readWriteLock.writeLock();

    private static int value;

    public void read(Lock lock) {
        lock.lock();
        SleepTools.sleepSecond(1);
        System.out.println("读完");
        lock.unlock();
    }

    public void write(Lock lock, int v) {
        lock.lock();
        SleepTools.sleepSecond(1);
        value = v;
        System.out.println("写完");
        lock.unlock();
    }

    public static void main(String[] args) {
        ReadWriteLock2 rt = new ReadWriteLock2();

        // 加读锁的时候, 其它的线程也可以获取到锁
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                rt.read(readLock);
            }).start();
        }

        // 写锁是独占
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                rt.write(writeLock, new Random().nextInt());
            }).start();
        }
    }
}

Semaphore

Semaphore 概述

Semaphore 通常我们叫它 信号量 使用 Semaphore 可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数

举个栗子

可以把它简单的理解成我们停车场入口立着的那个显示屏 每有一辆车进入停车场显示屏就会显示剩余车位 减1 每有一辆车从停车场出去,显示屏上显示的剩余车辆就会 加1 当显示屏上的剩余车位为 0 时,停车场入口的栏杆就不会再打开,车辆就无法进入停车场了,直到有一辆车从停车场出去为止

Semaphore 方法

方法名

作用

void acquire()

从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断

void release()

释放一个许可,将其返回给信号量

int availablePermits()

返回此信号量中当前可用的许可数

boolean hasQueuedThreads()

查询是否有线程正在等待获取

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 **/
public class Semaphore01 {

    public static void main(String[] args) {
        Semaphore s = new Semaphore(1);

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

                System.out.println("T1运行中...");
                System.out.println("当前已有" + s.availablePermits() + "个并发");

                Thread.sleep(200);
                System.out.println("T1运行中...");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("是否有人等待:" + s.hasQueuedThreads());

                System.out.println("T1即将离开");
                s.release();
            }
        }).start();

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

                System.out.println("T2 运行中...");
                System.out.println("当前有" + s.availablePermits() + "个并发");

                Thread.sleep(200);
                System.out.println("T2 运行中...");
                s.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println("是否有人等待:" + s.hasQueuedThreads());

                System.out.println("T2即将离开");
                s.release();
            }
        }).start();
    }
}

模拟一个需求:

停车场容纳总停车量 10 当一辆车进入停车场后,显示牌的剩余车位数相应的 减1 每有一辆车驶出停车场后,显示牌的剩余车位数相应的 加1 停车场剩余车位不足时,车辆只能在外面等待

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 **/
public class Semaphore02 {
    /**
     * 停车场同时容纳的车辆10
     */
    private static final Semaphore semaphore = new Semaphore(10);

    public static void main(String[] args) {
        // 模拟50辆车进入停车场
        for (int i = 0; i < 50; i++) {

            Thread thread = new Thread(() -> {
                try {

                    System.out.println("====" + Thread.currentThread().getName() + "来到停车场");

                    if (semaphore.availablePermits() == 0) {
                        System.out.println("车位不足,请耐心等待");
                    }

                    // 获取令牌尝试进入停车场
                    semaphore.acquire();

                    System.out.println(Thread.currentThread().getName() + "成功进入停车场");

                    // 模拟车辆在停车场停留的时间
                    Thread.sleep(new Random().nextInt(10000));

                    System.out.println(Thread.currentThread().getName() + "驶出停车场");

                    // 释放令牌,腾出停车场车位
                    semaphore.release();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, i + "号车");
            thread.start();
        }
    }
}

Exchanger

Exchanger 概述

Exchanger(交换者)是一个用于线程间协作的工具类 Exchanger 用于进行线程间的数据交换。它提供一个同步点,在这个同步点两个线程可以交换彼此的数据 这两个线程通过 exchange 方法交换数据,如果第一个线程先执行 exchange 方法 它会一直等待第二个线程也执行 exchange,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方

将纸制银流通过人工的方式录入成电子银行流水,为了避免错误,采用 AB 岗两人进行录入,录入到 Excel 之后,系统需要加载这两个 Excel,并对这两个 Excel 数据进行校对,看看是否录入的一致。

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 **/
public class Exchanger01 {
    private static Exchanger<String> ec = new Exchanger<>();

    private static ExecutorService threadPool = Executors.newFixedThreadPool(2);

    public static void main(String[] args) {
        threadPool.execute(() -> {
            try {
                // A录入银行流水数据
                String A = "银行流水A";

                String exchange = ec.exchange(A);

                System.out.println(exchange);
            } catch (InterruptedException e) {
            }
        });

        threadPool.execute(() -> {
            try {
                // B录入银行流水数据
                String B = "银行流水B";
                String A = ec.exchange(B);

                System.out.println("A和B数据是否一致:" + A.equals(B));

                System.out.println("A录入的是:" + A);
                System.out.println("B录入的是:" + B);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        
        threadPool.shutdown();
    }
}

LockSupport

LockSupport 是什么

LockSupport 是一个并发编程工具类,主要是为了阻塞和唤醒线程用的 可以让线程在任意位置阻塞,也可以在任意位置唤醒

LockSupport 方法

方法名

作用

park()

阻塞线程

unpark(需要唤醒的线程)

启动唤醒线程

LockSupport 与 wait 和 notify 的区别

获取锁

wait 和 notify 都是 Object 中的方法,在调用这两个方法前必须先获得锁对象 park 不需要获取某个对象的锁就可以锁住线程

唤醒

notify 只能随机选择一个线程唤醒 无法唤醒指定的线程,unpark 却可以唤醒一个指定的线程

代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class LockSupportTest1 {
    public static void main(String[] args) {

        Thread thread = new Thread(() -> {
            for (int i = 0; i < 10; i++) {

                System.out.println(i);

                if (i == 3) {
                    LockSupport.park();
                }

                SleepTools.sleepSecond(1);
            }
        });

        thread.start();
    }
}
代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class LockSupportTest1 {
    public static void main(String[] args) {

        Thread thread = new Thread(() -> {
            for (int i = 0; i < 10; i++) {

                System.out.println(i);

                if (i == 3) {
                    LockSupport.park();
                }

                SleepTools.sleepSecond(1);
            }
        });

        thread.start();

        // 先interrupt 时, 程序不会被阻塞
        thread.interrupt();
    }
}
代码语言:java
AI代码解释
复制
/**
 * @author BNTang
 */
public class LockSupportTest1 {
    public static void main(String[] args) {

        Thread thread = new Thread(() -> {
            for (int i = 0; i < 10; i++) {

                System.out.println(i);

                if (i == 3) {
                    LockSupport.park();
                }

                SleepTools.sleepSecond(1);
            }
        });

        thread.start();

        SleepTools.sleepSecond(1);
        // 当先执行unpark时, 程序不会被阻塞
        LockSupport.unpark(thread);
    }
}

我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
运用GPS北斗卫星时间同步技术应用数据采集系统
如今,数据采集系统很多,有基于数字信号处理器DSP设计的,也有基于现场可编程门阵列FPGA设计的,这些采集系统尽管采集处理数据能力不差,但大多都采用传统授时模式。而异地同步测量是工程中经常用到的方法,如果用传统的授时模式,其时钟频率的产生是用晶体,而晶体会老化,易受外界环境变化及长期的精度漂移影响,造成授时精度下降,这样异地同步测量的数据其实在理论上已经不再同步、同时了。本系统采用GPS新型授时方法,结合DSP技术和USB通信技术设计的数据采集系统能较好地解决这个问题。
NTP网络同步时钟
2020/12/14
1.2K0
运用GPS北斗卫星时间同步技术应用数据采集系统
同步STM32的SAI外设传输普通数据
一般同步ADC都是使用的FPGA,但是单片机也可以采集!虽然I2S和SAI都是传音频数据的,但其实可以传普通数据,本质都是二进制数据流嘛!(全网都没有相关的文章)
云深无际
2024/11/04
3570
同步STM32的SAI外设传输普通数据
嵌入式:万字详解通信接口设计
UART(Universal Asynchronous Receiver and Transmitter,通用异步收发器)是广泛使用的串行数据传输方式。
timerring
2023/01/10
1.2K0
嵌入式:万字详解通信接口设计
串口USART和UART「建议收藏」
UART是通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接受。UART主要用于主机与辅助设备通信。
全栈程序员站长
2022/08/31
2.5K0
嵌入式系统原理课后习题练习
(答案仅供参考,不喜勿喷~~) (本人比较懒,后面的就没仔细整) (注:如果你完成了我的“太懒啦”,我可以把你的加进去,附上你的名字,一起加油~~)
全栈程序员站长
2022/09/06
6.1K0
嵌入式系统原理课后习题练习
SPI协议,这篇就够了!
IIC支持热拔插吗?(附有详细CW32 IIC协议解读) 不知道你学会没有?我在这些低速实验写完以后会给出逻辑分析仪的调试步骤。
云深无际
2025/01/07
9810
SPI协议,这篇就够了!
串口通信详解
原理 计算机串行通信基础 随着多微机系统的广泛应用和计算机网络技术的普及,计算机的通信功能愈来愈显得重要。计算机通信是指计算机与外部设备或计算机与计算机之间的信息交换。 通信有并行通信和串行通信两种方式。在多微机系统以及现代测控系统中信息的交换多采用串行通信方式。 串行通信的基本概念 异步通信 异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程。为使双方的收发协调,要求发送和接收设备的时钟尽可能一致。
跋扈洋
2021/02/02
2.6K0
串口通信详解
STM32F103学习笔记三 串口通信
本文参照正点原子STM32F1xx官方资料:《STM32中文参考手册V10》-第25章通用同步异步收发器(USART) 及 【STM32】串口通信基本原理(超基础、详细版) 单片机入门学习十 STM32单片机学习七 串口通讯
全栈程序员站长
2022/11/07
2.3K0
CC2530基础实验四 串口通信
####一、任务要求 编写程序实现实验板定期向PC机串口发送字符串“Hello ! I am CC2530 。\n”。实验板开机后按照设定的时间间隔,不断地向PC及发送字符串,报告自己的状态,每发送一次字符串消息,LED1闪亮一次。具体工作方式如下:
w候人兮猗
2020/07/01
2.2K0
CC2530基础实验四     串口通信
【RL-TCPnet网络教程】第6章 RL-TCPnet底层驱动说明
本章节为大家讲解RL-TCPnet的底层驱动,主要是STM32自带MAC的驱动实现和PHY的驱动实现。
Simon223
2018/09/04
2K0
【RL-TCPnet网络教程】第6章    RL-TCPnet底层驱动说明
SPI 协议简介
SPI 协议是由摩托罗拉公司提出的通讯协议(Serial Peripheral Interface),即串行外围设 备接口,是一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间, 要求通讯速率较高的场合。
全栈程序员站长
2022/09/28
8.8K0
SPI 协议简介
stm32 spi协议_STM32库开发实战指南:基于STM32F4
✅作者简介:嵌入式入坑者,与大家一起加油,希望文章能够帮助各位!!!! 📃个人主页:@rivencode的个人主页 🔥系列专栏:玩转STM32 💬推荐一款模拟面试、刷题神器,从基础到大厂面试题👉点击跳转刷题网站进行注册学习 目录 一.SPI协议简介 二.SPI物理层 三.SPI协议层 1.通讯的起始和停止信号 2.数据有效性 3.时钟信号的相位和极性(重点) 四.SPI 特性及架构(重点) 1.通信引脚 2.时钟控制逻辑 3.数据控制逻辑(非常重要) 4.全双工发送和接收过程模式
全栈程序员站长
2022/11/03
9550
stm32 spi协议_STM32库开发实战指南:基于STM32F4
一文读懂使用MCU SPI访问具有非标准SPI接口ADC的方法
当前许多精密模数转换器(ADC)具有串行外设接口(SPI)或某种串行接口,用以与包括微控制器单元(MCU)、DSP和FPGA在内的控制器进行通信。控制器写入或读取ADC内部寄存器并读取转换码。SPI的印刷电路板(PCB)布线简单,并且有比并行接口更快的时钟速率,因而越来越受欢迎。而且,使用标准SPI很容易将ADC连接到控制器。
用户9736681
2022/05/11
1.3K1
一文读懂使用MCU SPI访问具有非标准SPI接口ADC的方法
DSP28335学习记录(一)
时钟通道图,CPU最高支持150M,需要配置的地方:OSCOFF、PLLCR、DIVSEL。
全栈程序员站长
2022/11/03
2K0
STM32-USART串口通信【USART和UART的区别】[通俗易懂]
这里只记主要关于STM32应用,不记原理,关于所有通信相关的物理和协议层面的详细知识总结将会放在【通信协议】专栏。
全栈程序员站长
2022/08/31
4.1K0
物联网-串口通信和ADC转换实验
USART是一个高度灵活的串行通讯设备。主要特点为:全双工操作 (独立的串行接收和发送寄存器)、异步或同步操作、主机或从机提供时钟的同步操作、高精度的波特率发生器、支持 5, 6, 7, 8,或 9个数据位和 1个或 2个停止位、硬件支持的奇偶校验操作、数据过速检测、帧错误检测、噪声滤波,包括错误的起始位检测,以及数字低通滤波器、三个独立的中断:发送结束中断、发送数据寄存器空中断,以及接收结束中断、多处理器通讯模式、倍速异步通讯模式。
会洗碗的CV工程师
2024/01/30
4610
物联网-串口通信和ADC转换实验
stm32串口工作原理_rs232串口通信原理
在同步通讯中,收发设备上方会使用一根信号线传输信号,在时钟信号的驱动下双方进行协调,同步数据。例如,通讯中通常双方会统一规定在时钟信号的上升沿或者下降沿对数据线进行采样。
全栈程序员站长
2022/10/04
1.2K0
stm32串口工作原理_rs232串口通信原理
TMS320C6000_TMS320F28035中文数据手册
大家好,我是架构君,一个会写代码吟诗的架构师。今天说一说TMS320C6000_TMS320F28035中文数据手册,希望能够帮助大家进步!!!
Java架构师必看
2022/07/12
1.1K0
第一章: 微型计算机组成结构
操作系统与所运行的硬件环境密切相关。如果想彻底理解操作系统运行全过程,那么就需要了解它的运行硬件环境。本章基于传统微机系统的硬件组成框图,介绍了微机中各个主要部分的功能。这些内容已基本能够建立起阅读Linux 0.11内核的硬件基础。为了便于说明,术语PC/AT将用来指示具有80386或以上CPU的IBMPC及其兼容微机,而PC则用来泛指所有微机,包括IBMPC/XT及其兼容微机。
大忽悠爱学习
2022/08/23
1.6K0
第一章: 微型计算机组成结构
ADC芯片——AD7705最详细讲解(STM32)「建议收藏」
读者必读:本人在专业实习的时候用到了外部ADC模块——AD7705,在使用的过程中参考过很多资料,有些资料非常有用,有些资料讲的有些小问题。 切记:一定要看英文芯片手册DataSheet,网上的AD7705中文手册也就参考一下。英文手册
全栈程序员站长
2022/08/03
8.4K0
ADC芯片——AD7705最详细讲解(STM32)「建议收藏」
推荐阅读
相关推荐
运用GPS北斗卫星时间同步技术应用数据采集系统
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档