展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > java中的synchronized是什么

java中的synchronized是什么

一、synchronized实现锁的表现形式修饰实例方法,对于普通同步方法,锁是当前的实例对象修饰静态方法,对于静态同步方法,锁是当前的Class对象修饰方法代码块,对于同步方法块,锁是synchronized括号里面配置的对象!当一个线程试图访问同步代码块的时候,就必须得到锁,完成后(或者出现异常),就必须释放锁。那么锁究竟存在什么地方呢?我们一块来探究!不过,相信,既然大家能够找到这篇文章,相信大家对他的使用早已了熟于心,我们对于使用,以及为什么多线程情况下,数据会出现错乱情况,不做详细的解释!只把他

本文目录

    一、synchronized实现锁的表现形式

    1. 修饰实例方法,对于普通同步方法,锁是当前的实例对象

    2. 修饰静态方法,对于静态同步方法,锁是当前的Class对象

    3. 修饰方法代码块,对于同步方法块,锁是synchronized括号里面配置的对象!

    当一个线程试图访问同步代码块的时候,就必须得到锁,完成后(或者出现异常),就必须释放锁。那么锁究竟存在什么地方呢?我们一块来探究!

    不过,相信,既然大家能够找到这篇文章,相信大家对他的使用早已了熟于心,我们对于使用,以及为什么多线程情况下,数据会出现错乱情况,不做详细的解释!只把他的几种使用方式列出,供参考!

    ①修饰实例方法

    修饰实例方法,对于普通同步方法,锁是当前的实例对象

    这个没得说,使用的同一个实例,添加上synchronized后,线程需要排队,完成一个原子操作,但是注意前提是使用的同一个实例,他才会生效!

    正例:

    /**
    * @author huangfu
    */
    public class ExploringSynchronized implements Runnable {
       /**
        * 共享资源(临界资源)
        */
       static int i=0;
       public synchronized void add(){
           i++;
       }

       @Override
       public void run() {
           for (int j = 0; j < 100000; j++) {
               add();
           }
       }

       public static void main(String[] args) throws InterruptedException {
           ExploringSynchronized exploringSynchronized = new ExploringSynchronized();
           Thread t1 = new Thread(exploringSynchronized);
           Thread t2 = new Thread(exploringSynchronized);
           t1.start();
           t2.start();
           //join 主线程需要等待子线程完成后在结束
           t1.join();
           t2.join();
           System.out.println(i);

       }
    }

    反例:

    /**
    * @author huangfu
    */
    public class ExploringSynchronized implements Runnable {
       /**
        * 共享资源(临界资源)
        */
       static int i=0;
       public synchronized void add(){
           i++;
       }

       @Override
       public void run() {
           for (int j = 0; j < 100000; j++) {
               add();
           }
       }

       public static void main(String[] args) throws InterruptedException {
           Thread t1 = new Thread(new ExploringSynchronized());
           Thread t2 = new Thread(new ExploringSynchronized());
           t1.start();
           t2.start();
           //join 主线程需要等待子线程完成后在结束
           t1.join();
           t2.join();
           System.out.println(i);

       }
    }

    这种,即使你在方法上加上了synchronized也无济于事,因为,对于普通同步方法,锁是当前的实例对象!实例对象都不一样了,那么他们之间的锁自然也就不是同一个!

    ②修饰静态方法

    修饰静态方法,对于静态同步方法,锁是当前的Class对象

    从定义上可以看出来,他的锁是类对象,那么也就是说,以上面那个类为例:普通方法的锁对象是 new ExploringSynchronized()而静态方法对应的锁对象是ExploringSynchronized.class所以对于静态方法添加同步锁,即使你重新创建一个实例,它拿到的锁还是同一个!

    package com.byit.test;

    /**
    * @author huangfu
    */
    public class ExploringSynchronized implements Runnable {
       /**
        * 共享资源(临界资源)
        */
       static int i=0;
       public synchronized static void add(){
           i++;
       }

       @Override
       public void run() {
           for (int j = 0; j < 100000; j++) {
               add();
           }
       }

       public static void main(String[] args) throws InterruptedException {
           Thread t1 = new Thread(new ExploringSynchronized());
           Thread t2 = new Thread(new ExploringSynchronized());
           t1.start();
           t2.start();
           //join 主线程需要等待子线程完成后在结束
           t1.join();
           t2.join();
           System.out.println(i);

       }
    }

    当然,结果是我们期待的  200000

    ③修饰方法代码块

    修饰方法代码块,对于同步方法块,锁是synchronized括号里面配置的对象!

    package com.byit.test;

    /**
    * @author huangfu
    */
    public class ExploringSynchronized implements Runnable {
       /**
        * 锁标记
        */
       private static final String LOCK_MARK = "LOCK_MARK";
       /**
        * 共享资源(临界资源)
        */
       static int i=0;
       public void add(){
           synchronized (LOCK_MARK){
               i++;
           }
       }

       @Override
       public void run() {
           for (int j = 0; j < 100000; j++) {
               add();
           }
       }

       public static void main(String[] args) throws InterruptedException {
           Thread t1 = new Thread(new ExploringSynchronized());
           Thread t2 = new Thread(new ExploringSynchronized());
           t1.start();
           t2.start();
           //join 主线程需要等待子线程完成后在结束
           t1.join();
           t2.join();
           System.out.println(i);

       }
    }

    对于同步代码块,括号里面是什么,锁对象就是什么,里面可以使用this  字符串  对象等等!

    二、synchronized的底层实现

    java中synchronized的实现是基于进入和退出的 Monitor对象实现的,无论是显式同步(修饰代码块,有明确的monitorenter和 monitorexit指令)还是隐式同步(修饰方法体)!

    需要注意的是,只有修饰代码块的时候,才是基于monitorenter和 monitorexit指令来实现的;修饰方法的时候,是通过另一种方式实现的!我会放到后面去说!

    在了解整个实现底层之前,我还是希望你能够大致了解一下对象在内存中的结构详情!

    java中的synchronized是什么

    • 实例变量:存放类的属性数据信息,包括父类的属性信息,如果是数组的实例部分还包括数组的长度,这部分内存按4字节对齐。

    • 填充数据:由于虚拟机要求对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐,这点了解即可。

    这两个概念,我们简单理解就好!我们今天并不去探究对象的构成原理!我们着重探究一下对象头,他对我们理解锁尤为重要!

    一般而言,synchronized使用的锁存在于对象头里面!如果是数组对象,则虚拟机使用3个字宽存储对象,如果是非数组对象,则使用两个字宽存储对象头!字虚拟机里面1字宽等于4字节!主要结构是 Mark Word 和 Class Metadata Address组成,结构如下:

    虚拟机位数头对象结构说明
    32/64bitMark Word存储对象的hashCode、锁信息或分代年龄或GC标志等信息
    32/64bitClass Metadata Address存储到队形类型数据的指针
    32/64bit(数组)Aarray length数组的长度

    通过上述表格能够看出  锁信息 存在于 Mark Word  内,那么 Mark Word 内又是如何组成的呢?

    锁状态25bit4bit1bit是否是偏向锁2bit锁标志位
    无锁状态对象的hashcode对象的分代年龄001

    在运行起见,mark Word 里存储的数据会随着锁的标志位的变化而变化。mark Word可能变化为存储一下四种数据

    java中的synchronized是什么

    Java SE 1.6为了减少获得锁和释放锁带来的消耗,引入了偏向锁和轻量级锁,从之前上来就是重量级锁到1.6之后,锁膨胀升级的优化,极大地提高了synchronized的效率;

    锁一共有4中状态,级别从低到高:

    java中的synchronized是什么

    这几个状态会随着锁的竞争,逐渐升级。锁可以升级,但是不能降级,其根本的原因就是为了提高获取锁和释放锁的效率!

    那么,synchronized是又如何保证的线程安全的呢?或许我们需要从字节码寻找答案!

    package com.byit.test;

    /**
    * @author Administrator
    */
    public class SynText {
       private static String A = "a";
       public int i ;

       public void add(){
           synchronized (A){
               i++;
           }

       }
    }

    反编译的字节码

    Compiled from "SynText.java"
    public class com.byit.test.SynText {
     public int i;

     public com.byit.test.SynText();
       Code:
          0: aload_0
          1: invokespecial #1                  // Method java/lang/Object."":()V
          4: return

     public void add();
       Code:
          0: getstatic     #2                  // Field A:Ljava/lang/String;
          3: dup
          4: astore_1
          5: monitorenter
          6: aload_0
          7: dup
          8: getfield      #3                  // Field i:I
         11: iconst_1
         12: iadd
         13: putfield      #3                  // Field i:I
         16: aload_1
         17: monitorexit
         18: goto          26
         21: astore_2
         22: aload_1
         23: monitorexit
         24: aload_2
         25: athrow
         26: return
       Exception table:
          from    to  target type
              6    18    21   any
             21    24    21   any

     static {};
       Code:
          0: ldc           #4                  // String a
          2: putstatic     #2                  // Field A:Ljava/lang/String;
          5: return
    }

    省去不必要的,简化在简化

       5: monitorenter
         ...
         17: monitorexit
         ...
         23: monitorexit

    从字节码中可知同步语句块的实现使用的是monitorenter和 monitorexit指令,其中monitorenter指令指向同步代码块的开始位置,monitorexit指令则指明同步代码块的结束位置,当执行monitorenter指令的时候,线程将试图获取对象所所对应的monitor特权,当monitor的的计数器为0的时候,线程就可以获取monitor,并将计数器设置为1.去锁成功!如果当前线程已经拥有monitor特权,则可以直接进入方法(可重入锁),计数器+1;如果其他线程已经拥有了monitor特权,那么本县城将会阻塞!

    拥有monitor特权的线程执行完成后释放monitor,并将计数器设置为0;同时执行monitorexit指令;不要担心出现异常无法执行monitorexit指令;为了保证在方法异常完成时 monitorenter 和 monitorexit 指令依然可以正确配对执行,编译器会自动产生一个异常处理器,这个异常处理器声明可处理所有的异常,它的目的就是用来执行 monitorexit 指令。从字节码中也可以看出多了一个monitorexit指令,它就是异常结束时被执行的释放monitor 的指令。

    同步代码块的原理了解了,那么同步方法如何解释?不急,我们不妨来反编译一下同步方法的状态!

    javap -verbose -p SynText > 3.txt

    代码

    package com.byit.test;

    /**
    * @author huangfu
    */
    public class SynText {
       public int i ;

       public synchronized void add(){
           i++;

       }
    }

    字节码

    Classfile /D:/2020project/byit-myth-job/demo-client/byit-demo-client/target/classes/com/byit/test/SynText.class
     Last modified 2020-1-6; size 382 bytes
     MD5 checksum e06926a20f28772b8377a940b0a4984f
     Compiled from "SynText.java"
    public class com.byit.test.SynText
     minor version: 0
     major version: 52
     flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
      #1 = Methodref          #4.#17         // java/lang/Object."":()V
      #2 = Fieldref           #3.#18         // com/byit/test/SynText.i:I
      #3 = Class              #19            // com/byit/test/SynText
      #4 = Class              #20            // java/lang/Object
      #5 = Utf8               i
      #6 = Utf8               I
      #7 = Utf8              
      #8 = Utf8               ()V
      #9 = Utf8               Code
     #10 = Utf8               LineNumberTable
     #11 = Utf8               LocalVariableTable
     #12 = Utf8               this
     #13 = Utf8               Lcom/byit/test/SynText;
     #14 = Utf8               syncTask
     #15 = Utf8               SourceFile
     #16 = Utf8               SynText.java
     #17 = NameAndType        #7:#8          // "":()V
     #18 = NameAndType        #5:#6          // i:I
     #19 = Utf8               com/byit/test/SynText
     #20 = Utf8               java/lang/Object
    {
     public int i;
       descriptor: I
       flags: ACC_PUBLIC

     public com.byit.test.SynText();
       descriptor: ()V
       flags: ACC_PUBLIC
       Code:
         stack=1, locals=1, args_size=1
            0: aload_0
            1: invokespecial #1                  // Method java/lang/Object."":()V
            4: return
         LineNumberTable:
           line 6: 0
         LocalVariableTable:
           Start  Length  Slot  Name   Signature
               0       5     0  this   Lcom/byit/test/SynText;

     public synchronized void syncTask();
       descriptor: ()V
       flags: ACC_PUBLIC, ACC_SYNCHRONIZED
       Code:
         stack=3, locals=1, args_size=1
            0: aload_0
            1: dup
            2: getfield      #2                  // Field i:I
            5: iconst_1
            6: iadd
            7: putfield      #2                  // Field i:I
           10: return
         LineNumberTable:
           line 10: 0
           line 11: 10
         LocalVariableTable:
           Start  Length  Slot  Name   Signature
               0      11     0  this   Lcom/byit/test/SynText;
    }
    SourceFile: "SynText.java"

    简化,在简化

     public synchronized void syncTask();
       descriptor: ()V
       flags: ACC_PUBLIC, ACC_SYNCHRONIZED
       Code:
         stack=3, locals=1, args_size=1
            0: aload_0
            1: dup

    我们能够看到 flags: ACC_PUBLIC, ACC_SYNCHRONIZED这样的一句话

    从字节码中可以看出,synchronized修饰的方法并没有monitorenter指令和monitorexit指令,取得代之的确实是ACC_SYNCHRONIZED标识,该标识指明了该方法是一个同步方法,JVM通过该ACC_SYNCHRONIZED访问标志来辨别一个方法是否声明为同步方法,从而执行相应的同步调用。这便是synchronized锁在同步代码块和同步方法上实现的基本原理。

    那么在JAVA6之前,为什么synchronized会如此的慢?

    那是因为,操作系统实现线程之间的切换需要系统内核从用户态切换到核心态!这个状态之间的转换,需要较长的时间,时间成本高!所以这也就是synchronized慢的原因!

    三、锁膨胀的过程

    在这之前,你需要知道什么是锁膨胀!他是JAVA6之后新增的一个概念!是一种针对之前重量级锁的一种性能的优化!他的优化,大部分是基于经验上的一些感官,对锁来进行优化!

    ①偏向锁

    研究发现,大多数情况下,锁不仅不存在多线程竞争,而且还总是由一条线程获得!因为为了减少锁申请的次数!引进了偏向锁!在没有锁竞争的情况下,如果一个线程获取到了锁,那么锁就进入偏向锁的模式!当线程再一次请求锁时,无需申请,直接获取锁,进入方法!但是前提是没有锁竞争的情况,存在锁竞争,锁会立即膨胀,膨胀为轻量级锁!

    ②轻量级锁

    偏向锁失败,那么锁膨胀为轻量级锁!此时锁机构变为轻量级锁结构!他的经验依据是:“绝大多数情况下,在整个同步周期内,不会存在锁的竞争”,故而,轻量级锁适合,线程交替进行的场景!如果在同一时间出现两条线程对同一把锁的竞争,那么此时轻量级锁就不会生效了!但是,jdk官方为了是锁的优化性能更好,轻量级锁失效后,并不会立即膨胀为重量级锁!而是将锁转换为自旋锁状态!

    ③自旋锁

    轻量级锁失败后,为了是避免线程挂起,引起内核态的切换!为了优化,此时线程会进入自选状态!他可能会进行几十次,上百次的空轮训!为什么呢?又是经验之谈!他们认为,大多数情况下,线程持有锁的时间都不会太长!做几次空轮训,就能大概率的等待到锁!事实证明,这种优化方式确实有效!最后如果实在等不到锁!没办法,才会彻底升级为重量级锁!

    ④锁消除

    jvm在进行代码编译时,会基于上下文扫描;将一些不可能存在资源竞争的的锁给消除掉!这也是JVM对于锁的一种优化方式!不得不感叹,jdk官方的脑子!举个例子!在方法体类的局部变量对象,他永远也不可能会发生锁竞争,例如:

    /**
    * @author huangfu
    */
    public class SynText {
       public static void add(String name1 ,String name2){
           StringBuffer sb = new StringBuffer();
           sb.append(name1).append(name2);
       }

       public static void main(String[] args) {
           for (int i = 0; i < 10000000; i++) {
               add("w"+i,"q"+i);
           }
       }
    }

    不能否认,StringBuffer是线程安全的!但是他永远也不会被其他线程引用!故而,锁失效!故而,被消除掉!

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    IntelliJ IDEA macOS版
    IntelliJ IDEA macOS版

    IntelliJ IDEA 是 JetBrains 推出的专业集成开发环境,重点服务于 Java、Kotlin 与 JVM 项目开发。软件集成代码补全、静态检查、重构、调试、测试、版本控制及构建工具,并可借助插件扩展语言和框架支持。

    PyCharm macOS版
    PyCharm macOS版

    JetBrains PyCharm 是面向 Python 开发者的集成开发环境,提供智能补全、代码检查、重构、调试、测试、版本控制及虚拟环境管理功能。Mac 版兼容 Intel 与 Apple 芯片,核心功能可免费使用。

    WebStorm macOS版
    WebStorm macOS版

    JetBrains WebStorm 是面向 JavaScript、TypeScript 和现代 Web 技术的专业集成开发环境,可智能理解项目结构,提供代码补全、重构、错误检查、运行调试、测试及 Git 工具。

    After Effects macOS版
    After Effects macOS版

    Adobe After Effects 是面向动态图形、影视特效与视频合成的专业创作软件。它提供关键帧动画、遮罩抠像、运动跟踪、三维空间、文字动画和表达式等工具,并可与 Premiere Pro、Photoshop、Illustrator

    Audition macOS版
    Audition macOS版

    Adobe Audition 是面向播客、影视后期、音乐制作及内容创作者的专业音频工作站,提供波形精修、多轨录制与混音、频谱编辑、降噪修复、响度匹配和效果处理工具,并可与 Adobe Premiere 协同完成视频声音制作。

    Bridge macOS版
    Bridge macOS版

    Adobe Bridge 是面向摄影师、设计师及内容团队的免费数字资产管理工具,可集中预览照片、视频和 Adobe 项目文件,并利用评级、标签、关键词、元数据、筛选与收藏集完成分类检索。它还支持批量重命名、格式导出、相机导入及 Camera

    Illustrator macOS版
    Illustrator macOS版

    Adobe Illustrator 是 Adobe 推出的专业矢量图形设计软件,适合在 Mac 上制作标志、图标、插画、包装、信息图及印刷版面。它以路径和锚点构建可无损缩放的图形,并提供钢笔、形状、文字、图像描摹、渐变、画板及生成式功能。

    InDesign macOS版
    InDesign macOS版

    Adobe InDesign 是面向印刷品与数字出版物的专业版面设计软件,可在 Mac 上制作书籍、杂志、宣传册、海报、报告及交互式文档。它提供精细的文字样式、网格、母版、长文档管理和印前输出能力。

    Lightroom Classic macOS版
    Lightroom Classic macOS版

    Adobe Lightroom Classic 是面向桌面摄影工作流的照片管理与后期处理软件,可将原始照片保存在本地硬盘,通过目录、关键词、评分和收藏夹高效整理图库,并提供 RAW 冲印、蒙版、镜头校正、批量同步及多格式导出等功能。

    Media Encoder macOS版
    Media Encoder macOS版

    Adobe Media Encoder 是 Adobe 推出的专业音视频编码与转码工具,可通过队列、预设和监视文件夹批量完成格式转换、代理文件创建及多平台成片输出,并与 Premiere Pro、After Effects 等软件紧密协作。

    Photoshop macOS版
    Photoshop macOS版

    Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理软件,提供图层、蒙版、选区、修复、调色、文字排版、智能对象及生成式编辑等能力。Mac 版支持 Intel 与 Apple Silicon 处理器。

    Premiere Pro macOS版
    Premiere Pro macOS版

    Adobe Premiere Pro 是面向专业视频制作的非线性剪辑软件,提供多轨时间线、调色、音频处理、字幕、代理工作流和多格式输出能力,并可与 After Effects、Audition、Photoshop 及 Frame.io 协同

    WINDOWS 更多
    IntelliJ IDEA Windows版
    IntelliJ IDEA Windows版

    JetBrains IntelliJ IDEA 是以 Java、Kotlin 和 JVM 项目为核心的专业集成开发环境,提供智能补全、代码检查、安全重构、调试、测试、版本控制及构建工具集成。统一发行版的核心功能可免费用于商业和非商业项目,

    PhpStorm Windows版
    PhpStorm Windows版

    PhpStorm 是 JetBrains 面向 PHP 与现代 Web 开发打造的专业集成开发环境,提供代码补全、静态检查、重构、调试、测试、数据库、版本控制及前端语言支持。Windows 用户可直接下载安装程序,

    PyCharm Windows版
    PyCharm Windows版

    PyCharm 是 JetBrains 推出的 Python 集成开发环境,提供智能代码补全、错误检查、重构、调试、测试、Git、终端及 Jupyter Notebook 支持。统一版安装后可体验 30 天 Pro 功能,

    WebStorm Windows版
    WebStorm Windows版

    WebStorm 是 JetBrains 面向 JavaScript、TypeScript 和现代 Web 技术打造的集成开发环境。它提供项目级代码分析、智能补全、安全重构、导航搜索,并集成调试、测试、终端、Git 与常用前端工具,

    Photoshop Windows版
    Photoshop Windows版

    Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理工具,可在 Windows 上完成照片修饰、选区抠图、图层合成、文字排版、绘画及生成式编辑。软件采用订阅授权,由 Creative Cloud 管理安装、更新与许

    InDesign Windows版
    InDesign Windows版

    Adobe InDesign 是面向印刷与数字出版的专业页面排版工具,可制作书籍、杂志、宣传册、海报、交互式 PDF 和电子书。它提供精细的文字样式、多页面管理、印前检查及多格式输出能力,并能与 Photoshop、Illustrator

    Illustrator Windows版
    Illustrator Windows版

    Adobe Illustrator 是用于绘制矢量图形、插画、图标、徽标和版式的专业设计工具。它以路径和锚点为核心,作品放大后仍能保持清晰,并提供画板、文字、渐变、图像描摹及精确变换等功能,适合品牌视觉、印刷物料、数字界面和商业插画创作。

    Bridge Windows版
    Bridge Windows版

    Adobe Bridge 是 Adobe 推出的创意资产管理工具,可集中预览、分类和查找照片、视频、PDF及多种设计文件,并支持元数据、关键词、评级、批量重命名和格式导出。它可与 Photoshop、Illustrator 等应用衔接,

    Lightroom Classic Windows版
    Lightroom Classic Windows版

    Adobe Lightroom Classic 是面向 Windows 桌面摄影工作流的照片管理与无损编辑工具,可通过目录集中整理大型图库,并完成 RAW 显影、局部蒙版、批量调整、打印和多格式导出。它强调本地文件管理与精细控制,

    Acrobat Pro Windows版
    Acrobat Pro Windows版

    Adobe Acrobat Pro 是面向专业 PDF 工作的综合解决方案,可在 Windows 中创建、编辑、转换、比较、整理和保护文档,并支持表单、电子签名、扫描件文字识别及敏感信息永久遮盖。订阅还包含网页、移动服务和云端协作能力,

    After Effects Windows版
    After Effects Windows版

    Adobe After Effects 是面向动态图形、动画与影视视觉特效制作的专业工具,可完成关键帧动画、图层合成、遮罩跟踪、抠像、文字动画和二维三维元素整合。Windows 版通过 Adobe Creative Cloud 安装及更新,

    Media Encoder Windows版
    Media Encoder Windows版

    Adobe Media Encoder 是 Adobe 面向视频与音频制作流程提供的专业编码和转码工具,可批量处理媒体文件、创建代理、套用输出预设并监控文件夹自动执行任务。它与 Premiere、After Effects、Audition