Java知识复习(四)多线程、并发编程
1、进程、线程和程序
- 进程:进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的;在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程中的一个线程,也称主线程
- 线程:线程与进程相似,但线程是一个比进程更小的执行单位;与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈;简单来说就是进程有资源,而线程几乎没有,它只是一个调度的单位,资源使用的是进程的
- 程序:指含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码,一个可执行的文件
2、虚拟机栈和本地方法栈为什么是私有的?
- 虚拟机栈:每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程
- 本地方法栈:和虚拟机栈的作用相似,不同的是为使用到的Native方法服务(Native方法指用其他语言,比如c实现的方法)
- 所以,为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的
3、线程的生命周期
- 初始状态:线程被创建出来,但没有被调用
- 运行状态:线程被调用了start()等待运行的状态(这里包括了就绪和运行中两种状态)
- 阻塞状态:需要等待锁被释放
- 等待状态:表示该线程需要等待其他线程做出一些特定动作(通知或中断)
- 超时等待状态:可以在指定的时间后自行返回
- 终止状态:表示该线程已经运行完毕
注意: 这里没有区分就绪和运行两种状态是因为现代操作系统的时间片太小了,以至于区分二者没有太多意义。
4、上下文切换
- 上下文:线程在执行过程中会有自己的运行条件和状态,比如上文所说到过的程序计数器,栈信息等
- 上下文切换:在线程切换时保存当前线程的上下文,留待线程下次占用 CPU 的时候恢复现场,并加载下一个将要占用 CPU 的线程上下文
5、线程死锁
1、线程死锁:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放
2、四个必要条件:简单来说就是:“你不松手我也不松手”
- 互斥条件:该资源任意一个时刻只由一个线程占用。
- 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:线程已获得的资源在未使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
- 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。
6、预防死锁和死锁避免
1、预防死锁:破坏四个必要条件之一
2、避免死锁:银行家算法
7、sleep()方法和wait()方法
- 共同点:都可以暂停线程的执行
- 不同点:sleep方法没有释放锁,而wait方法释放了锁;sleep方法执行后,线程会自动苏醒,而wait方法需要notify方法唤醒;sleep是Thread类的静态本地方法,而wait是Object类的本地方法
8、可以直接调用Thread类的run方法吗
回答: 调用 start() 方法方可启动线程并使线程进入就绪状态,当分配到时间片后就可以开始自动执行run()方法,但如果直接执行 run() 方法的话不会以多线程的方式执行,而是被当做main线程下的一个普通方法去执行
9、volatile关键字
- volatile关键字可以保证变量的可见性,指示JVM这个变量共享且不稳定,每次使用它都得到主存中进行读取
- 还有一个作用就是防止JVM的指令重排序
- volatile关键字不能保证对变量的操作是原子性的,但synchronized可以
10、乐观锁和悲观锁
1、乐观锁:总是假设最好的情况,认为共享资源每次被访问的时候不会出现问题,线程可以不停地执行,无需加锁也无需等待,只是在提交修改的时候去验证对应的资源(也就是数据)是否被其它线程修改了(具体方法可以使用版本号机制或 CAS 算法)
- 通常用于读比较多的情况
- 版本号机制:每次修改数据都会更新版本号,每次提交更新数据时会比较版本号,只有版本号一致时才更新
- CAS算法:全称Compare And Swap(比较与交换),思想就是用一个预期值和要更新的变量值进行比较,两值相等才会进行更新;CAS是一条原子操作,因此当多个线程同时使用 CAS 操作一个变量时,只有一个会胜出,并成功更新,其余均会失败,但失败的线程并不会被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作
2、悲观锁:总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁,这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放(例如synchronized的独占锁);通常用于写比较多的情况
11、乐观锁存在的问题
1、ABA问题: 如果一个变量 V 初次读取的时候是 A 值,并且在准备赋值的时候检查到它仍然是 A 值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回 A,那 CAS 操作就会误认为它从来没有被修改过。
解决思路: ABA 问题的解决思路是在变量前面追加上版本号或者时间戳
2、循环时间长开销大: CAS 经常会用到自旋操作来进行重试,也就是不成功就一直循环执行直到成功。如果长时间不成功,会给 CPU 带来非常大的执行开销
解决思路: 使用处理器提供的pause指令延迟流水线执行指令
3、只能保证一个共享变量的原子操作: CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效
解决思路: 我们可以使用锁或者利用AtomicReference类把多个共享变量合并成一个共享变量来进行CAS操作
12、synchronized关键字
1、synchronized(同步): 主要解决的是多个线程之间访问资源的同步性,可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行
2、使用方式:
- 修饰实例方法:锁当前对象实例加锁,进入同步代码前要获得当前对象实例的锁
- 修饰静态方法:给当前类加锁,会作用于类的所有对象实例 ,进入同步代码前要获得当前 class 的锁
- 修饰代码块:对括号里指定的对象/类加锁
synchronized(object/类.class)
:表示进入同步代码库前要获得给定对象或者类的锁 - 注意:构造方法不能用synchronized关键字修饰,因为构造方法本身就属于线程安全的
13、synchronized和volatile有什么区别
- synchronized 关键字和 volatile 关键字是两个互补的存在,而不是对立的存在!
- volatile 关键字是线程同步的轻量级实现,所以 volatile性能肯定比synchronized关键字要好。但是 volatile 关键字只能用于变量而 synchronized 关键字可以修饰方法以及代码块
- volatile 关键字能保证数据的可见性,但不能保证数据的原子性。synchronized 关键字两者都能保证
- volatile关键字主要用于解决变量在多个线程之间的可见性,而 synchronized 关键字解决的是多个线程之间访问资源的同步性
14、公平锁和非公平锁
- 公平锁 : 锁被释放之后,先申请的线程先得到锁。性能较差一些,因为公平锁为了保证时间上的绝对顺序,上下文切换更频繁
- 非公平锁 :锁被释放之后,后申请的线程可能会先获取到锁,是随机或者按照其他优先级排序的。性能更好,但可能会导致某些线程永远无法获取到锁
15、可中断锁和不可中断锁
- 可中断锁 :获取锁的过程中可以被中断,不需要一直等到获取锁之后 才能进行其他逻辑处理。ReentrantLock 就属于是可中断锁
- 不可中断锁 :一旦线程申请了锁,就只能等到拿到锁以后才能进行其他的逻辑处理。 synchronized 就属于是不可中断锁
16、ThreadLocal
1、ThreadLocal类: 主要解决的就是让每个线程绑定自己的值
- 可以将ThreadLocal类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据
- 如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的本地副本,这也是ThreadLocal变量名的由来
- 他们可以使用 get() 和 set() 方法来获取默认值或将其值更改为当前线程所存的副本的值,从而避免了线程安全问题
2、ThreadLocalMap: 最终的变量是放在了当前线程的 ThreadLocalMap 中,并不是存在 ThreadLocal 上,ThreadLocal 可以理解为只是ThreadLocalMap的封装,传递了变量值
- 每个Thread中都具备一个ThreadLocalMap,而ThreadLocalMap可以存储以ThreadLocal为 key ,Object 对象为 value 的键值对
3、内存泄漏:
- ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用,而 value 是强引用
- 如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候,key 会被清理掉,而 value 不会被清理掉
- 这样一来,ThreadLocalMap 中就会出现 key 为 null 的 Entry。假如我们不做任何措施的话,value 永远无法被 GC 回收,这个时候就可能会产生内存泄露
- ThreadLocalMap 实现中已经考虑了这种情况,在调用 set()、get()、remove() 方法的时候,会清理掉 key 为 null 的记录。使用完 ThreadLocal方法后 最好手动调用remove()方法
17、线程池
1、线程池: 顾名思义,线程池就是管理一系列线程的资源池。当有任务要处理时,直接从线程池中获取线程来处理,处理完之后线程并不会立即被销毁,而是等待下一个任务
2、创建方法:
- 方式一:通过ThreadPoolExecutor构造函数来创建(推荐)
- 方式二:通过 Executor 框架的工具类 Executors 来创建
18、Future类
1、Future类: 是异步思想的典型运用,主要用在一些需要执行耗时任务的场景,避免程序一直原地等待耗时任务执行完成,执行效率太低
2、简单理解就是: 我有一个任务,提交给了 Future 来处理。任务执行期间我自己可以去做任何想做的事情。并且,在这期间我还可以取消任务以及获取任务的执行状态。一段时间之后,我就可以 Future 那里直接取出任务执行结果
19、AQS
1、AQS: 全称为 AbstractQueuedSynchronizer ,翻译过来的意思就是抽象队列同步器,为构建锁和同步器提供了一些通用功能的实现
2、AQS的核心原理: 如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态;如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制 AQS 是用 CLH 队列锁 实现的,即将暂时获取不到锁的线程加入到队列中
- CLH 队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)
- 使用 int 成员变量 state 表示同步状态,通过内置的 线程等待队列 来完成获取资源线程的排队工作
20、Semaphore
1、synchronized 和 ReentrantLock 都是一次只允许一个线程访问某个资源,而Semaphore(信号量)可以用来控制同时访问特定资源的线程数量
2、Semaphore的原理: 是共享锁的一种实现,它默认构造 AQS 的 state 值为 permits,你可以将 permits 的值理解为许可证的数量,只有拿到许可证的线程才能执行
21、CountDownLatch和CyclicBarrier关键字
1、CountDownLatch 的作用就是 允许 count 个线程阻塞在一个地方,直至所有线程的任务都执行完毕
2、CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是:让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活
3、CyclicBarrier 和 CountDownLatch 非常类似,它也可以实现线程间的技术等待,但是它的功能比 CountDownLatch 更加复杂和强大
22、线程的常用方法
- 线程睡眠:sleep方法,休眠一会儿,睡到自然醒
- 线程等待:wait方法,停下别动,等待通知
- 线程让步:yield方法,让出CPU时间片给优先级高的线程
- 线程中断:interrupt方法,修改内部维护的中断标识符,但不会直接打断一个正在运行的线程
- 线程加入:join方法,等待子线程执行结束
- 线程唤醒:notify方法,动起来,开始干活
- 后台守护线程:setDaemon方法,提供公共服务,默默干些杂活,比如垃圾回收线程
参考
- Java并发常见面试题总结
- 《Offer来了:Java面试核心知识点》
相关文章:
Java知识复习(四)多线程、并发编程
1、进程、线程和程序 进程:进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的;在 Java 中,当我们启动 main 函数时其实就是启动了一个 JVM 的进程,而 main 函数所在的线程就是这个进程…...
一个9个月测试经验的人,居然在面试时跟我要18K,我都被他吓到了····
2月初我入职了深圳某家创业公司,刚入职还是很兴奋的,到公司一看我傻了,公司除了我一个测试,公司的开发人员就只有3个前端2个后端还有2个UI,在粗略了解公司的业务后才发现是一个从零开始的项目,目前啥都没有…...
zigbee与WIFI同频干扰问题
zigbee与WIFI同频干扰 为了降低Wifi信道与Zigbee信道的同频干扰问题,Zigbee联盟在《Zigbee Home Automation Public Application Profile》中推荐使用11,14,15,19,20,24,25这七个信道。 为什么呢,我们看一下Wifi和Zigbee的信道分布。 WiFi带宽对干扰的…...
git拉取指定的单个或多个文件或文件夹
直接上步骤 初始化仓库 git init拉取远程仓库信息,省略号为仓库地址 git remote add -f origin http://****.git开启 sparse clone git config core.sparsecheckout true配置需要拉取的文件夹 有一个指定一个,有多个指定多个,路径写对即可&a…...
不是,到底有多少种图片懒加载方式?
一、也是我最开始了解到的 js方法,利用滚动事件,判断当时的图片位置是否在可视框内,然后进行渲染。 弊端:代码冗杂,你还要去监听页面的滚动事件,这本身就是一个不建议监听的事件,即便是我们做了…...
CAD坐标有哪些输入方式?来看看这些CAD坐标输入方式!
在CAD设计过程中,有时需要通过已知坐标点来画图,有时又需要通过已知角度和距离来画图,在这种情况下,由于已知条件不同,所以便需要用不同的方式来定位点。那么,你知道CAD坐标有哪些输入方式吗?本…...
铰链、弹簧,特殊的物理关节
title: 铰链、弹簧,特殊的物理关节 date: 2023-02-28T13:32:57Z lastmod: 2023-02-28T14:24:06Z 铰链关节(Hinge Join)组件 组件-Physics-Hinge Join Anchor 当物体挂载铰链组件以后,组件下Anchor等同于边长为1的立方体。当这…...
Android Studio相关记录
目录Android Studio 便捷插件Android LogcatJava文件的类头模板Android Studio 使用遇到的问题解决方案org.jetbrains.annotations.NullableBuild 控制台编译输出中文乱码Terminal 使用 git 命令窗口git 命令窗口中文乱码Android Studio 便捷插件 Android Logcat 配置路径 Fi…...
Linux 基础介绍-基础命令
文章目录01 学习目标02 Linux/Unix 操作系统简介2.1 Linux 操作系统的目标2.2 Linux 操作系统的作用2.3 Unix 家族历史2.4 Linux 家族历史2.5 Linux 和Unix 的联系2.6 Linux 内核介绍2.7 Linux 发行版本2.8 Unix/Linux 开发应用领域介绍03 Linux 目录结构3.1 Win 和Linux 文件系…...
Linux 进程:程序地址空间 与 虚拟内存
目录一、程序地址空间二、虚拟地址空间1.虚拟内存的原理2.使用虚拟内存的原因?3.如何实现虚拟空间?4.使用虚拟内存的好处本文主要介绍程序地址空间和虚拟地址空间的概念,理解了虚拟地址空间,才可以更好的理解物理内存和进程pcb之间…...
python 密码学编程
最近在看一本书。名字是 python密码学编程。在此做一些笔记,同时也为有需要的人提供一些参考。 ******************************************************************** * quote : "http://inventwithpython.com/" …...
【C++ | bug | 运算符重载】定义矩阵(模板)类时,使用 “友元函数” 进行 * 运算符重载时编译报错
作者:非妃是公主 专栏:《C》 博客地址:https://blog.csdn.net/myf_666 个性签:顺境不惰,逆境不馁,以心制境,万事可成。——曾国藩 文章目录专栏推荐一、类的声明及函数定义二、错误信息三、问题…...
数学小课堂:无穷小(以动态的眼光看待世界,理解无限的世界)
文章目录 引言I 芝诺四个著名的悖论1.1 二分法悖论:从A点到B点是不可能的。1.2 阿喀琉斯悖论:阿喀琉斯追不上乌龟。1.3 飞箭不动悖论:射出去的箭是静止的。1.4 基本空间和相对运动悖论II 回答芝诺的悖论2.1 阿喀琉斯悖论2.2 相对运动悖论III 无穷小3.1 无穷小的定义3.1 无穷…...
leetcode 427. Construct Quad Tree(构建四叉树)
刚看到题的时候是懵的,这也太长了。到底是要表达什么呢。 不妨把这个矩阵看成一个正方形的图片,想象你在处理图片,从整体逐步到局部。 刚开始看一整张图片,如果是全0或全1,这个就是叶子节点,怎么表达叶子节…...
Spring Boot 3.0系列【2】部署篇之使用GraalVM构建原生镜像
有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot版本2.7.0 文章目录概述JIT & AOTJIT (动态编译)AOT(静态编译)GraalVM简介运行模式Native Image(原生镜像)…...
复习知识点十之方法的重载
目录 方法的重载 练习1: 练习1: 数组遍历 练习2: 数组的最大值 练习3: 练习4: 复制数组 基本数据类型和引用数据类型 方法的重载 Java虚拟机会通过参数的不同来区分同名的方法 练习1: public class Test4 {public static void main(String[] args) {//调用方法 // …...
火爆全网的ChatGPT 和AI 可以为项目经理做什么?
作为一款人工智能聊天机器人,ChatGPT因其逼真和人性化的特性而风靡全球,无疑是当今技术的新流行。人工智能 (AI) 有可能彻底改变许多行业,包括项目管理,及时了解最新技术以及它如何影响你的工作至关重要。于是,我们与C…...
前端面试题 —— HTML
目录 一、src 和 href 的区别 二、对 HTML 语义化的理解 三、DOCTYPE(⽂档类型) 的作⽤ 四、script 标签中 defer 和 async 的区别 五、常⽤的 meta 标签有哪些? 六、HTML5 有哪些更新 八、行内元素有哪些?块级元素有哪些? 空(void)元素…...
同为(TOWE)电源线让家用电器随心放置
如今,随着科技水平的不断发展,人们工作、生活中越来越离不开各类电子设备和电器产品。当用电器数量多了以后,由于电器设备原有电线长度的限制,常常需要通过连接接线板来延长电器设备的电能传输线路。电源线虽然看着是一件不起眼的…...
2023上半年数学建模竞赛汇总(报名时间、比赛时间、难易程度、含金量、竞赛官网)
1、美国大学生数学建模竞赛等级:国家级是否可跨校:否竞赛开始时间:2月17日~2月21日综合难度:⭐⭐⭐⭐ 竞赛含金量:⭐⭐⭐⭐⭐竞赛官网:https://www.comap.com/2、MathorCup高校数学建模挑战赛---大数据竞赛…...
RK3568平台开发系列讲解(驱动基础篇)SMP(Symmetrical Multi-Processing)
🚀返回专栏总目录 文章目录 一、linux SMP 和 AMP二、linux SMP的启动流程三、CPU的描述:cpumask四、CPU之间的关系沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍 SMP(Symmetrical Multi-Processing)。 一、linux SMP 和 AMP 目前支持多核处理器的实时操…...
HIVE --- zeppelin安装
目录 把zeppelin压缩包拷贝到虚拟机里面 解压 改名 修改配置文件 编辑zeppelin-site.xml—将配置文件的ip地址和端口号进行修改 编辑 zeppelin-env.sh—添加JDK和Hadoop环境 配置环境变量 刷新环境变量 拷贝Hive文件 拷贝外部文件 启动zeppelin 启动Hadoop&Hi…...
数据分析中的变量解释
1.数值变量Numerical Variables 数值型变量(metric variable)是说明事物数字特征的一个名称,其取值是数值型数据。如“产品产量”、“商品销售额”、“零件尺寸”、“年龄”、“时间”等都是数值型变量,这些变量可以取不同的数值…...
django-博客(一)
一、 1、环境:pycharm,python3.6,django3,mysql8.0 2、创建项目 3、把html和css样式那些导入到文件夹中,然后配置这些文件夹的路径,再添加首页视图。 改成反向解析 python manage.py runserv…...
Shell高级——Linux中的文件描述符
以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。 前言 Linux中一切接文件,比如 C 源文件、视频文件、Shell脚本、可执行文件等,就连键盘、显示器、鼠标等硬件设备也都是文件。 一个 Linux 进程可以打开成百上…...
洗地机哪个品牌最好用?家用洗地机十大名牌
这几年清洁类的小家电非常热门,无线吸尘器、扫地机器人、扫拖一体机、洗地机和擦窗机器人层出不穷,各个品牌百花齐放。这些清洁电器,确实为家庭卫生清洁带来了很大的便捷。但要把这些产品一次性买齐是一笔不小的开销,而且需要收纳…...
java多线程(十)线程休眠
一、sleep()介绍 sleep() 定义在Thread.java中。 sleep() 的作用是让当前线程休眠,即当前线程会从“运行状态”进入到“休眠(阻塞)状态”。sleep()会指定休眠时间,线程休眠的时间会大于/等于该休眠时间;在线程重新被唤醒时,它会由…...
Leetcode20. 有效的括号
一、题目描述: 给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。左括号必须以正确…...
Android 项目必备(四十三)-->Android 开发者的 new 电脑
前言 作为 Android 开发者,当你新入职一家公司,拿到新发的电脑,你会对电脑干点啥? 安装开发环境?装软件?你是否还会铺天盖地到处找之前电脑备份的东西?又或者还想不起来有什么上一台电脑好用的…...
如何水平和垂直居中元素
跳到主内容 我试图将我的选项卡内容垂直居中,但是当我添加 CSS 样式时display:inline-flex,水平文本对齐消失了。 如何为每个选项卡同时对齐文本 x 和 y? * { box-sizing: border-box; } #leftFrame {background-color: green;position: a…...
wordpress外链url/seo关键词排名优化怎么样
目前Java中switch语句支持的数据类型包括:byte、short、int、char、String以及Enum,那么switch语句是如何实现的呢?一、switch对整型的支持public void switchInt(int value) {switch (value) {case 1:System.out.println("1");bre…...
响应式网站缺点/电商平台的推广及运营思路
2019独角兽企业重金招聘Python工程师标准>>> 第1部分:说明 最近在做一个类似微信语音聊天的功能,在屏幕的底部放一个Button,按下时可以语音说话,松开时将语音发出去。但是做的过程中遇到一个坑:按钮放到页面…...
怎样搭建一个网站/百度自然排名优化
福师11春学期《计算机应用基础》在线作业二试卷总分:100 测试时间:--单选题多选题一、单选题(共40 道试题,共80 分。)V 1. 下列不能对数据表排序的是:( )○A. 单击数据区中任一单元格,然后单击工具栏中升序"或&qu…...
科郑州网站建设/重庆公司seo
「Jetpack - Lifecycle梳理」 本文已参与「新人创作礼」活动,一起开启掘金创作之路 一、写在前面 谷歌推出Jetpack系列已经有一段时间了,作为AAC(Android Architecture Components)架构组件基础,使开发的过程越来越规范化,遵循…...
独立网站需要多少钱/杭州搜索引擎排名
一、首先,明确以下内容: 1.http连接池不是万能的,过多的长连接会占用服务器资源,导致其他服务受阻 2.http连接池只适用于请求是经常访问同一主机(或同一个接口)的情况下 3.并发数不高的情况下资源利用率低下 那么,当你的业务符合上面3点,那么你可以考虑使用http连接池来提高服…...
网站建设客户问到的问题/建网站的公司
XYPieChart创建动态饼 关键字:饼图 动态饼图 代码类库:绘图(Drawing) GitHub链接:https://github.com/xyfeng/XYPieChart 可以帮你简单地创建动态饼图。所有的动画都是用drawRect:方法实现。可自定义颜色文本标签选项显示实际值或者百分比当一…...