JUC实战之利用JUC解决问题

JUC组件实战:实现Java与硬件(通过MQTT)的同步通信 本文结合JUC下的Lock、Condition与Future实现MQTT同步通信的组件其中Lock与Condition是为了阻塞等待,但程序中的DefaultFuture是当作局部变量被使用的,并不存在并发因此,如果只是为了等待而加锁是没必要的,可以考虑使用LockSupport.park/unpark进行等待但是LockSupport.unpark唤醒时需要具体的线程,因此需要增加一个容器对任务与业务线程进行绑定存储。 阅读详情

题目1 使用3个线程循环打印10遍ABC

方案一

    public static void main(String[] args) {

        Maj maj = new Maj();

        Thread a = new Thread(new ThreadABC(maj,"A"));
        Thread b = new Thread(new ThreadABC(maj,"B"));
        Thread c = new Thread(new ThreadABC(maj,"C"));

        a.start();
        b.start();
        c.start();

    }

    static class  ThreadABC implements Runnable{

        private String content;

        private Maj maj;

        public ThreadABC(Maj maj, String content) {
            this.content = content;
            this.maj = maj;
        }

        @Override
        public void run(){
            try{
                while (true){
                    if(maj.cnt_a == 10 && maj.cnt_b == 10 && maj.cnt_c == 10){
                        break;
                    }
                    synchronized (maj){

                        switch (content){
                            case "A":
                                if(maj.cnt_a == maj.cnt_b && maj.cnt_a == maj.cnt_c){
                                    System.out.println(content);
                                    maj.cnt_a++;
                                    maj.notifyAll();
                                }else {
                                    maj.wait();
                                }
                            break;

                            case "B":
                                if(maj.cnt_a > maj.cnt_b && maj.cnt_b == maj.cnt_c){
                                    System.out.println(content);
                                    maj.cnt_b++;
                                    maj.notifyAll();
                                }else {
                                    maj.wait();
                                }
                                break;
                            case "C":
                                if(maj.cnt_a > maj.cnt_c && maj.cnt_a > maj.cnt_c){
                                    System.out.println(content);
                                    maj.cnt_c++;
                                    maj.notifyAll();
                                }else {
                                    maj.wait();
                                }
                                break;
                        }
                    }

                }
            }catch (Exception ex){

            }
        }
    }

    static class Maj {
        public volatile int cnt_a = 0;
        public volatile int cnt_b = 0;
        public volatile int cnt_c = 0;
    }

但是注意这个方案其实是错误的。会导致程序卡死。但这个仍然是唯一可行的方案。其实严格按照题目要求是不可实现的。

如果我们允许修改原题目给的模版,那么这个就变成了很轻松实现实现的东西。方案二

package org.luzhen.test;
 
import java.awt.image.VolatileImage;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
/**
 * @Author: luzhen
 * @Date: 2019-02-12 13:09
 * @Version 1.0
 */
public class ConditionTest {
 
    static Lock lock = new ReentrantLock();
    final static Condition condition1 = lock.newCondition();
    final static Condition condition2 = lock.newCondition();
    final static Condition condition3 = lock.newCondition();
    private volatile int state = 0;
 
 
    public static void main(String[] args) {
        ConditionTest conditionTest = new ConditionTest();
        
        new Thread(() -> {
            conditionTest.printA("A", 0,1, condition1, condition2);
        }).start();
 
        new Thread(() -> {
            conditionTest.printA("B", 1,2, condition2, condition3);
        }).start();
 
        new Thread(() -> {
            conditionTest.printA("C", 2,0, condition3, condition1);
        }).start();
    }
 
    /**
     * 
     * @param s 打印的字符串内容
     * @param inParameter 初始化的state入参值
     * @param expectNextState 控制打印顺序的开关 让对应的哪个线程执行打印
     * @param currentCondition 由于3个condition 会创建3个阻塞队列 代表当前condition所对应的那个阻塞队列
     * @param nextCondition 通知我们规定的那个线程 从对应的等待队列里进入同步队列中 获取锁 执行打印
     */
    public void printA(String s, int inParameter,int expectNextState, Condition currentCondition, Condition nextCondition) {
        for (int i = 0; i < 10; i++) {
            try {
                lock.lock();
                while (state != inParameter) {
                    currentCondition.await();
                }
                System.out.println(s);
                state = expectNextState;
                nextCondition.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}

题目二

写一个简单的callable和future的使用

public class Test {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        Task task = new Task();
        Future<Integer> result = executor.submit(task);
        executor.shutdown();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        System.out.println("主线程在执行任务");

        try {
            System.out.println("task运行结果"+result.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        System.out.println("所有任务执行完毕");
    }
}
class Task implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("子线程在进行计算");
        Thread.sleep(3000);
        int sum = 0;
        for(int i=0;i<100;i++)
            sum += i;
        return sum;
    }
}

题目三 描述下concurrentHashMap中的ReentrantLock的使用

ConcurrentHashMap中的segment作为ReentrantLock的包装。

    static class Segment<K,V> extends ReentrantLock implements Serializable {
        private static final long serialVersionUID = 2249069246763182397L;
        final float loadFactor;
        Segment(float lf) { this.loadFactor = lf; }
    }

必须清楚,JDK8中的segment已经被遗弃了。现在保留这个纯属序列化兼容需要。
那我们看看JDK7中的使用呢?

    public V put(K key, V value) {
        Segment<K,V> s;
        if (value == null)
            throw new NullPointerException();
        int hash = hash(key.hashCode());
        int j = (hash >>> segmentShift) & segmentMask;
        if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck
                (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment
            s = ensureSegment(j);
        return s.put(key, hash, value, false);
    }

可见putvalue最后调用的是segment的put

        final V put(K key, int hash, V value, boolean onlyIfAbsent) {
            HashEntry<K,V> node = tryLock() ? null :
                    scanAndLockForPut(key, hash, value);
            V oldValue;
            try {
                HashEntry<K,V>[] tab = table;
                int index = (tab.length - 1) & hash;
                HashEntry<K,V> first = entryAt(tab, index);
                for (HashEntry<K,V> e = first;;) {
                    if (e != null) {
                        K k;
                        if ((k = e.key) == key ||
                                (e.hash == hash && key.equals(k))) {
                            oldValue = e.value;
                            if (!onlyIfAbsent) {
                                e.value = value;
                                ++modCount;
                            }
                            break;
                        }
                        e = e.next;
                    }
                    else {
                        if (node != null)
                            node.setNext(first);
                        else
                            node = new HashEntry<K,V>(hash, key, value, first);
                        int c = count + 1;
                        if (c > threshold && tab.length < MAXIMUM_CAPACITY)
                            rehash(node);
                        else
                            setEntryAt(tab, index, node);
                        ++modCount;
                        count = c;
                        oldValue = null;
                        break;
                    }
                }
            } finally {
                unlock();
            }
            return oldValue;
        }

        private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
            HashEntry<K,V> first = entryForHash(this, hash);
            HashEntry<K,V> e = first;
            HashEntry<K,V> node = null;
            int retries = -1; // negative while locating node
            while (!tryLock()) {
                HashEntry<K,V> f; // to recheck first below
                if (retries < 0) {
                    if (e == null) {
                        if (node == null) // speculatively create node
                            node = new HashEntry<K,V>(hash, key, value, null);
                        retries = 0;
                    }
                    else if (key.equals(e.key))
                        retries = 0;
                    else
                        e = e.next;
                }
                else if (++retries > MAX_SCAN_RETRIES) {
                    lock();
                    break;
                }
                else if ((retries & 1) == 0 &&
                        (f = entryForHash(this, hash)) != first) {
                    e = first = f; // re-traverse if entry changed
                    retries = -1;
                }
            }
            return node;
        }

可见,当put value抢不到锁的时候,就会循环等待。如果循环若干次也不行吗,那么就直接调用lock来等待锁。

题目四 写一些JUC中锁的例子来证明你懂

  • Semaphore
import java.util.concurrent.ExecutorService;     
import java.util.concurrent.Executors;     
import java.util.concurrent.Semaphore;     
    
public class TestSemaphore {     
    
    public static void main(String[] args) {     
        // 线程池     
        ExecutorService exec = Executors.newCachedThreadPool();     
    
        // 只能5个线程同时访问     
    
        final Semaphore semp = new Semaphore(5);     
    
        // 模拟20个客户端访问     
        for (int index = 0; index < 20; index++) {     
            final int NO = index;     
            Runnable run = new Runnable() {     
                public void run() {     
                    try {     
                        // 获取许可     
                        semp.acquire();     
    
                        System.out.println("Accessing: " + NO);     
    
                        Thread.sleep((long) (Math.random() * 10000));     
    
                        // 访问完后,释放     
                        semp.release();     
                    } catch (InterruptedException e) {     
    
                    }     
    
                }     
    
            };     
            exec.execute(run);     
        }     
    
        // 退出线程池     
        exec.shutdown();     
    }     
}  
  • CountDownLatchDemo
package com.example.demo.CountDownLatchDemo;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 主线程等待子线程执行完成再执行
 */
public class CountdownLatchTest1 {
    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 = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("子线程" + Thread.currentThread().getName() + "开始执行");
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("子线程"+Thread.currentThread().getName()+"执行完成");
                        latch.countDown();//当前线程调用此方法,则计数减一
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            service.execute(runnable);
        }

        try {
            System.out.println("主线程"+Thread.currentThread().getName()+"等待子线程执行完成...");
            latch.await();//阻塞当前线程,直到计数器的值为0
            System.out.println("主线程"+Thread.currentThread().getName()+"开始执行...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • CyclicBarrier
public class CyclicBarrierDemo {

    static class TaskThread extends Thread {
        
        CyclicBarrier barrier;
        
        public TaskThread(CyclicBarrier barrier) {
            this.barrier = barrier;
        }
        
        @Override
        public void run() {
            try {
                Thread.sleep(1000);
                System.out.println(getName() + " 到达栅栏 A");
                barrier.await();
                System.out.println(getName() + " 冲破栅栏 A");
                
                Thread.sleep(2000);
                System.out.println(getName() + " 到达栅栏 B");
                barrier.await();
                System.out.println(getName() + " 冲破栅栏 B");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    public static void main(String[] args) {
        int threadNum = 5;
        CyclicBarrier barrier = new CyclicBarrier(threadNum, new Runnable() {
            
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " 完成最后任务");
            }
        });
        
        for(int i = 0; i < threadNum; i++) {
            new TaskThread(barrier).start();
        }
    }
    
}
JUC线程框架深度解析 — 01、JUC基础使用 一、JUC开发包简介【 java.util.concurrent开发包 】➣ 传统线程编程模型之中为防止死锁等现象的出现(wait()、notify()、   synchronized)时往往会考虑性能、公平性、资源管理等问题,这样加重了程序开发人员的负担;➣ Java5.0添加了一个新的java.util.concurrent开发包(简称JUC)。   利用此包进行的多线程编程将有效的减少竞争条... 阅读详情

相关推荐

Java利用JUC包创建线程的三种方式

Future接口用于表示异步计算的结果,通过它可以取消任务、查询任务是否完成、获取任务的结果等。它可以用于表示一个异步计算的结果,也可以用于执行异步任务并处理任务完成后的结果。Executor框架提供了一种管理线程的高级机制,可以轻松地创建和管理线程池。通过Executor框架,可以将任务提交给线程池,线程池会负责管理线程的生命周期。// 创建一个固定大小的线程池。这些都是使用JUC包中提供的类来创建线程的方式,它们提供了更高级别的抽象和功能,能够更方便地管理线程和处理并发任务。

weixin_45811927的博客 2146

JUC实战必备-全是精华

????JUC 简介 JAVA 在 1.5版本中引入了 java.util.concurrent工具包,JUC 就是它的简称,用于处理线程的工具包。 ????重温进程与线程 进程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;进程——资源分配的最小单位。 线程:系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。线程——程序执行的最小单位。 线程的状态 NEW:新建 RUNNABLE:准备就绪 BLOCKED:阻塞 WAITING:等待(不见不散) TIMED_WAITIN

weixin_43206491的博客 1164

JUC详解 | JUC概述

JUC就是在 Java 5.0 提供了 `java.util.concurrent`(简称JUC)包,在此包中增加了在并发编程中很常用的工具类。此包包括了几个小的、已标准化的可扩展框架,并提供一些功能实用的类,没有这些类,一些功能会很难实现或实现起来冗长乏味。

蕤荥的成长博客 8643

JUC篇——CompletableFuture实现异步编排,涵盖全部编排功能API,详细讲解异步编排实战场景,一篇文章彻底拿下!

CompletableFuture介绍:CompletableFuture 是 Java 8 中新增的一个异步编程工具类,基于 Future 和 CompletionStage 接口构建。它支持 lambda,通过回调利用非阻塞方法,提升了异步编程模型。主要用于异步执行任务并返回结果,实现异步计算和操作组合。它提供了一种灵活、可组合的方式来实现异步计算,同时也提供了异常处理、取消、超时等特性。

我热爱学习,也乐于分享。无论是科技前沿的洞见,还是生活中的小技巧,我都会在这里与你分享。我相信,知识就是力量,而分享则能让这份力量得到更好的传递。 2079

JUC 高并发编程的入门学习

课程内容概览 什么是 JUC Lock 接口 线程间通信 集合的线程安全 多线程锁 Callable 接口 JUC 三大辅助类: CountDownLatch CyclicBarrier Semaphore 读写锁: ReentrantReadWriteLock 阻塞队列 ThreadPool 线程池 Fork/Join 框架 CompletableFuture 1 什么是 JUC 1.1 JUC 简介 在 Java 中,线程部分是一个重点,本篇文章说的 JUC 也是关于线程的。JUC就是 java.u

aa35434的博客 1393

【Java之多线程】JUC常见知识点全面总结_juc 考点

大部分情况下使用就足够了锁竞争激烈的时候,使用, 搭配trylock方法可以更灵活地控制加锁的行为,而不是死等。如果需要使用公平锁, 使用信号量Semaphore一般用来表示可用资源的个数,相当于一个计数器,可类比生活中停车场牌子上面显示的停车场剩余车位数量。当有车开进去的时候, 就相当于申请一个可用资源,可用车位就 -1 (这个称为信号量的 P 操作)当有车开出来的时候, 就相当于释放一个可用资源, 可用车位就 +1 (这个称为信号量的 V 操作)

2401_84618023的博客 1223

JUC并发包深度解析:原理、示例与实战场景(一文教会)

:维护等待线程的CLH队列。

✨ 欢迎来唠嗑、切磋、一起成长!👋 1046

JUC全解析:一篇文章让你精通JUC

JUC是Java提供的用于并发编程的强大工具包。通过掌握JUC的核心组件、常用实践和最佳实践,我们可以更加高效地利用多核处理器的计算能力,构建高效、可靠的并发应用。希望本文能够帮助读者精通JUC,并在实际开发中灵活运用这些工具。

专业深耕,技术前沿 1588

JUC并发编程面试题

文章目录1. 并行和并发有什么区别?2. 线程和进程的基本概念、线程的基本状态以及状态之间的关系?3.守护线程是什么?4.创建线程有哪几种方式?5. sleep() 和 wait() 有什么区别?6.线程的 run() 和 start() 有什么区别?7.创建线程池有哪几种方式?8.在 Java 程序中怎么保证多线程的运行安全?9.什么是死锁?怎么防止死锁?10.synchronized 和 volatile 的区别是什么?11.synchronized 和 Lock 有什么区别?12.synchroniz

weixin_45081813的博客 3890

狂神说JUC.pdf

Bilibili狂神老师的JUC课程笔记,讲的非常的好,希望大家结合视频学习狂神老师的JUC编程,精进自己的技术。

java并发编程专题(八)----(JUC)实例讲解CountDownLatch

主要介绍了java CountDownLatch的相关资料,文中示例代码非常详细,帮助大家理解和学习,感兴趣的朋友可以了解下

JUC全面解析-一文带你掌握JUC

本文深入解析了Java并发工具包(JUC)的核心概念和实践应用。从线程池的创建与管理到原子操作类,再到锁机制和并发集合的使用,每个部分都通过详实的讲解帮助读者全面掌握JUC的关键知识点。我们将通过对CAS机制、AQS(抽象队列同步器)、各种同步工具(如CountDownLatch、CyclicBarrier、Semaphore)、ForkJoin框架等的讲解

weixin_67796933的博客 7835

QCC308X/518X/309X加LDAC解码

QCC308X/518X/309X加LDAC解码。

Alex_886的博客 6609

【JUC基础学习笔记】

JUC基础学习笔记一、JUC概述1. JUC是什么2. 进程与线程3. 并发与并行4. sleep() 和 wait()等方法二、Lock1. Synchronized2. Lock接口与方法3. 两者异同4. Lock接口重要实现类三、线程通信 / 线程同步1. Synchronized同步块2. Lock锁四、线程安全1. 阻塞同步2. 非阻塞同步3. 非同步五、集合的线程安全1. 并发集合 ArrayList2. Vector3. Collections4. JUC.CopyOnWriteList..

sixteen_16的博客 1万+

iOS开发者必备:从越狱设备里提取IPA的三种方法(含Filza、iTools实战)

本文详细介绍了iOS开发者从越狱设备提取IPA文件的三种实用方法,包括使用Filza文件管理器、AFC2配合桌面工具以及命令行高级技术。内容涵盖环境准备、操作步骤和技术原理,帮助开发者高效获取应用包文件,适用于逆向工程、测试分析等场景。

weixin_28717969的博客 815

UE4/5编译报错MSB3073终极解决指南:从路径检查到MSVC版本降级

本文针对UE4/5开发中常见的MSB3073编译报错,提供了一套从根源到实战的终极解决指南。文章系统性地讲解了错误成因,并分层次指导排查路径字符、环境变量、MSVC版本兼容性、权限冲突等核心问题,重点介绍了通过降级MSVC编译器版本等关键操作来彻底解决此编译难题。

rl6adventurer的博客 1435

【JUC基础】01. 初步认识JUC

前段时间,有朋友跟我说,能否写一些关于JUC的教程文章。本来呢,JUC也有在我的专栏计划之内,只是一直都还没空轮到他,那么既然有这样的一个契机,那就把JUC计划提前吧。那么今天就重点来初步认识一下什么是JUC,以及一些基本的JUC相关基础知识。

有一只柴犬的专栏 1653

UFS软件分区介绍

本文主要介绍了ufs软件分区管理的概况,能够使大家对软件分区有个大体的认识

肥匪斐's blogs 1万+

什么是JUC?

什么是JUC?

m0_61787196的博客 1775

化工设计软件:AutoCAD Plant 3D二次开发_(1).AutoCADPlant3D概述

AutoCAD Plant 3D 是一款专为化工行业设计的三维工厂设计和建模软件。它基于AutoCAD平台,提供了强大的三维建模功能和专业的化工设计工具,帮助工程师和设计师在工厂设计过程中提高效率和准确性。AutoCAD Plant 3D不仅能够创建详细的三维模型,还可以进行管道设计、设备布置、支架设计等复杂任务。通过上述案例,我们可以看出 AutoCAD Plant 3D 在化工厂设计中的强大功能和优势。该软件不仅提供了丰富的建模工具和专业的设计功能,还支持二次开发,使用户能够根据具体需求进行定制化操作。

kkchenjj的博客 1103

YOLO系列算法改进 | C3k2改进篇 | 融合DEConv细节增强卷积模块 | 细节增强+多分支差分卷积融合,标准卷积的完美涨点替代! | TIP 2024

YOLO系列算法改进 | C3k2改进篇 | 融合DEConv细节增强卷积模块 | 细节增强+多分支差分卷积融合,标准卷积的完美涨点替代! | TIP 2024 (以YOLO26最新目标检测模型为基础,融合C3k2_DEConv创新模块进行改进)

2502_91881744的博客 310

JUC详解

什么是JUC? JUC其实就是JDK中的三个包: java.util.concurrent 并发相关的 java.util.concurrent.atomic 原子性 java.util.concurrent.locks lock锁 Runnable 没有返回值,效率相比Callable相对较低。 进程:一个程序,QQ,Music.exe 程序的集合 ;一个进程可以包含多个线程,至少包含一个。 Java默认有几个线程? 2个 main线程和GC线程(做垃圾回收) Java可以开启

weixin_53379153的博客 1万+

机器人中的数值优化(二十一)—— 伴随灵敏度分析、线性方程组求解器的分类和特点、优化软件

本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考,主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等,本系列文章篇数较多,不定期更新,上半部分介绍无约束优化,下半部分介绍带约束的优化,中间会穿插一些路径规划方面的应用实例

慕羽★的博客 4205

java--JUC快速入门(彻底搞懂JUC)

线程池:一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。

qq_53808097的博客 4161

Vue+OpenLayers:解决中国境内OpenStreetMap地图加载问题

然而,在使用OpenLayers和Vue框架搭建地图应用时,很多中国开发者可能会遇到一个常见问题:OpenStreetMap(OSM)地图无法正常加载。为了解决这个问题,我们可以使用其他方式获取地图数据,比如使用国内的地图服务提供商。通过使用国内地图服务商提供的地图数据,我们可以解决OpenStreetMap地图加载问题。然后,我们创建一个OpenLayers地图对象,并指定地图图层的源为国内地图服务商提供的地图URL。属性,可以将地图的中心点和缩放级别调整到我们需要的位置。

CodeWhizZ的博客 8273

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

JUC在高并发电商系统中的应用实战

这次实战让我深刻体会到JUC组件的强大之处。它们提供了丰富的工具来解决各种并发问题,而且性能优异。选择合适的并发工具很重要,不要过度设计分布式环境下要考虑更多因素压力测试要尽早做,持续做监控和日志是关键如果你也在开发类似的高并发系统,不妨试试InsCode(快马)平台,它的一键部署功能让测试变得特别方便。我经常用它来快速验证想法,省去了搭建环境的麻烦。平台内置的编辑器也很顺手,支持多人协作,对团队开发很友好。

SapphireOwl29的博客 929

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

上一篇: SPI和类加载器
下一篇: JAVA多线程之wait&notify&notifyAll
define_us
博客等级 码龄14年 157粉丝 531原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值