精华内容
下载资源
问答
  • 详解synchronizedLock的区别与使用

    万次阅读 多人点赞 2017-03-22 13:12:02
    想起自己在上次面试也遇到了synchronizedLock的区别与使用。于是,我整理了两者的区别使用情况,同时,对synchronized的使用过程一些常见问题的总结,最后是参照源码和说明文档,对Lock的使用写了几个简单的Demo...

    ###引言:
    昨天在学习别人分享的面试经验时,看到Lock的使用。想起自己在上次面试也遇到了synchronized与Lock的区别与使用。于是,我整理了两者的区别和使用情况,同时,对synchronized的使用过程一些常见问题的总结,最后是参照源码和说明文档,对Lock的使用写了几个简单的Demo。请大家批评指正。

    技术点:

    1、线程与进程:

    在开始之前先把进程与线程进行区分一下,一个程序最少需要一个进程,而一个进程最少需要一个线程。关系是线程–>进程–>程序的大致组成结构。所以线程是程序执行流的最小单位,而进程是系统进行资源分配和调度的一个独立单位。以下我们所有讨论的都是建立在线程基础之上。

    2、Thread的几个重要方法:

    我们先了解一下Thread的几个重要方法。a、start()方法,调用该方法开始执行该线程;b、stop()方法,调用该方法强制结束该线程执行;c、join方法,调用该方法等待该线程结束。d、sleep()方法,调用该方法该线程进入等待。e、run()方法,调用该方法直接执行线程的run()方法,但是线程调用start()方法时也会运行run()方法,区别就是一个是由线程调度运行run()方法,一个是直接调用了线程中的run()方法!!

    看到这里,可能有些人就会问啦,那wait()和notify()呢?要注意,其实wait()与notify()方法是Object的方法,不是Thread的方法!!同时,wait()与notify()会配合使用,分别表示线程挂起和线程恢复。

    这里还有一个很常见的问题,顺带提一下:wait()与sleep()的区别,简单来说wait()会释放对象锁而sleep()不会释放对象锁。这些问题有很多的资料,不再赘述。

    3、线程状态:

    这里写图片描述

    线程总共有5大状态,通过上面第二个知识点的介绍,理解起来就简单了。

    • 新建状态:新建线程对象,并没有调用start()方法之前

    • 就绪状态:调用start()方法之后线程就进入就绪状态,但是并不是说只要调用start()方法线程就马上变为当前线程,在变为当前线程之前都是为就绪状态。值得一提的是,线程在睡眠和挂起中恢复的时候也会进入就绪状态哦。

    • 运行状态:线程被设置为当前线程,开始执行run()方法。就是线程进入运行状态

    • 阻塞状态:线程被暂停,比如说调用sleep()方法后线程就进入阻塞状态

    • 死亡状态:线程执行结束

    4、锁类型

    • 可重入锁:在执行对象中所有同步方法不用再次获得锁

    • 可中断锁:在等待获取锁过程中可中断

    • 公平锁: 按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁权利

    • 读写锁:对资源读取和写入的时候拆分为2部分处理,读的时候可以多线程一起读,写的时候必须同步地写


    ###synchronized与Lock的区别

    1、我把两者的区别分类到了一个表中,方便大家对比:

    类别synchronizedLock
    存在层次Java的关键字,在jvm层面上是一个类
    锁的释放1、以获取锁的线程执行完同步代码,释放锁 2、线程执行发生异常,jvm会让线程释放锁在finally中必须释放锁,不然容易造成线程死锁
    锁的获取假设A线程获得锁,B线程等待。如果A线程阻塞,B线程会一直等待分情况而定,Lock有多个锁获取的方式,具体下面会说道,大致就是可以尝试获得锁,线程可以不用一直等待
    锁状态无法判断可以判断
    锁类型可重入 不可中断 非公平可重入 可判断 可公平(两者皆可)
    性能少量同步大量同步
    或许,看到这里还对LOCK所知甚少,那么接下来,我们进入LOCK的深入学习。
    

    ###Lock详细介绍与Demo

    以下是Lock接口的源码,笔者修剪之后的结果:

    public interface Lock {
    
        /**
         * Acquires the lock.
         */
        void lock();
    
        /**
         * Acquires the lock unless the current thread is
         * {@linkplain Thread#interrupt interrupted}.
         */
        void lockInterruptibly() throws InterruptedException;
    
        /**
         * Acquires the lock only if it is free at the time of invocation.
         */
        boolean tryLock();
    
        /**
         * Acquires the lock if it is free within the given waiting time and the
         * current thread has not been {@linkplain Thread#interrupt interrupted}.
         */
        boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    
        /**
         * Releases the lock.
         */
        void unlock();
    	
    }
    
    从Lock接口中我们可以看到主要有个方法,这些方法的功能从注释中可以看出:
    
    • lock():获取锁,如果锁被暂用则一直等待

    • unlock():释放锁

    • tryLock(): 注意返回类型是boolean,如果获取锁的时候锁被占用就返回false,否则返回true

    • tryLock(long time, TimeUnit unit):比起tryLock()就是给了一个时间期限,保证等待参数时间

    • lockInterruptibly():用该锁的获得方式,如果线程在获取锁的阶段进入了等待,那么可以中断此线程,先去做别的事

    通过 以上的解释,大致可以解释在上个部分中“锁类型(lockInterruptibly())”,“锁状态(tryLock())”等问题,还有就是前面子所获取的过程我所写的“大致就是可以尝试获得锁,线程可以不会一直等待”用了“可以”的原因。

    下面是Lock一般使用的例子,注意ReentrantLock是Lock接口的实现。
    

    lock():

    
    package com.brickworkers;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class LockTest {
    	private Lock lock = new ReentrantLock();
    
    	//需要参与同步的方法
    	private void method(Thread thread){
    		lock.lock();
    		try {
    			System.out.println("线程名"+thread.getName() + "获得了锁");
    		}catch(Exception e){
    			e.printStackTrace();
    		} finally {
    			System.out.println("线程名"+thread.getName() + "释放了锁");
    			lock.unlock();
    		}
    	}
    	
    	public static void main(String[] args) {
    		LockTest lockTest = new LockTest();
    		
    		//线程1
    		Thread t1 = new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				lockTest.method(Thread.currentThread());
    			}
    		}, "t1");
    		
    		Thread t2 = new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				lockTest.method(Thread.currentThread());
    			}
    		}, "t2");
    		
    		t1.start();
    		t2.start();
    	}
    }
    //执行情况:线程名t1获得了锁
    //         线程名t1释放了锁
    //         线程名t2获得了锁
    //         线程名t2释放了锁
    

    tryLock():

    package com.brickworkers;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class LockTest {
    	private Lock lock = new ReentrantLock();
    
    	//需要参与同步的方法
    	private void method(Thread thread){
    /*		lock.lock();
    		try {
    			System.out.println("线程名"+thread.getName() + "获得了锁");
    		}catch(Exception e){
    			e.printStackTrace();
    		} finally {
    			System.out.println("线程名"+thread.getName() + "释放了锁");
    			lock.unlock();
    		}*/
    		
    		
    		if(lock.tryLock()){
    			try {
    				System.out.println("线程名"+thread.getName() + "获得了锁");
    			}catch(Exception e){
    				e.printStackTrace();
    			} finally {
    				System.out.println("线程名"+thread.getName() + "释放了锁");
    				lock.unlock();
    			}
    		}else{
    			System.out.println("我是"+Thread.currentThread().getName()+"有人占着锁,我就不要啦");
    		}
    	}
    	
    	public static void main(String[] args) {
    		LockTest lockTest = new LockTest();
    		
    		//线程1
    		Thread t1 = new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				lockTest.method(Thread.currentThread());
    			}
    		}, "t1");
    		
    		Thread t2 = new Thread(new Runnable() {
    			
    			@Override
    			public void run() {
    				lockTest.method(Thread.currentThread());
    			}
    		}, "t2");
    		
    		t1.start();
    		t2.start();
    	}
    }
    
    //执行结果: 线程名t2获得了锁
    //         我是t1有人占着锁,我就不要啦
    //         线程名t2释放了锁
    
    

    看到这里相信大家也都会使用如何使用Lock了吧,关于tryLock(long time, TimeUnit unit)和lockInterruptibly()不再赘述。前者主要存在一个等待时间,在测试代码中写入一个等待时间,后者主要是等待中断,会抛出一个中断异常,常用度不高,喜欢探究可以自己深入研究。

    前面比较重提到“公平锁”,在这里可以提一下ReentrantLock对于平衡锁的定义,在源码中有这么两段:
    
    
     /**
         * Sync object for non-fair locks
         */
        static final class NonfairSync extends Sync {
            private static final long serialVersionUID = 7316153563782823691L;
    
            /**
             * Performs lock.  Try immediate barge, backing up to normal
             * acquire on failure.
             */
            final void lock() {
                if (compareAndSetState(0, 1))
                    setExclusiveOwnerThread(Thread.currentThread());
                else
                    acquire(1);
            }
    
            protected final boolean tryAcquire(int acquires) {
                return nonfairTryAcquire(acquires);
            }
        }
    
        /**
         * Sync object for fair locks
         */
        static final class FairSync extends Sync {
            private static final long serialVersionUID = -3000897897090466540L;
    
            final void lock() {
                acquire(1);
            }
    
            /**
             * Fair version of tryAcquire.  Don't grant access unless
             * recursive call or no waiters or is first.
             */
            protected final boolean tryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                if (c == 0) {
                    if (!hasQueuedPredecessors() &&
                        compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
                else if (current == getExclusiveOwnerThread()) {
                    int nextc = c + acquires;
                    if (nextc < 0)
                        throw new Error("Maximum lock count exceeded");
                    setState(nextc);
                    return true;
                }
                return false;
            }
        }
    

    从以上源码可以看出在Lock中可以自己控制锁是否公平,而且,默认的是非公平锁,以下是ReentrantLock的构造函数:

       public ReentrantLock() {
            sync = new NonfairSync();//默认非公平锁
        }
    

    ###尾记录:

    笔者水平一般,不过此博客在引言中的目的已全部达到。这只是笔者在学习过程中的总结与概括,如存在不正确的,欢迎大家批评指出。
    

    延伸学习:对于LOCK底层的实现,大家可以参考:
    点击Lock底层介绍博客

    两种同步方式性能测试,大家可以参考:
    点击查看两种同步方式性能测试博客

    ##博主18年3月新增:
    回来看自己博客。发现东西阐述的不够完整。这里在做补充,因为这篇博客访问较大,所以为了不误导大家,尽量介绍给大家正确的表述:
    1、两种锁的底层实现方式:
    synchronized:我们知道java是用字节码指令来控制程序(这里不包括热点代码编译成机器码)。在字节指令中,存在有synchronized所包含的代码块,那么会形成2段流程的执行。
    这里写图片描述

    我们点击查看SyncDemo.java的源码SyncDemo.class,可以看到如下:
    这里写图片描述

    如上就是这段代码段字节码指令,没你想的那么难吧。言归正传,我们可以清晰段看到,其实synchronized映射成字节码指令就是增加来两个指令:monitorenter和monitorexit。当一条线程进行执行的遇到monitorenter指令的时候,它会去尝试获得锁,如果获得锁那么锁计数+1(为什么会加一呢,因为它是一个可重入锁,所以需要用这个锁计数判断锁的情况),如果没有获得锁,那么阻塞。当它遇到monitorexit的时候,锁计数器-1,当计数器为0,那么就释放锁。

    那么有的朋友看到这里就疑惑了,那图上有2个monitorexit呀?马上回答这个问题:上面我以前写的文章也有表述过,synchronized锁释放有两种机制,一种就是执行完释放;另外一种就是发送异常,虚拟机释放。图中第二个monitorexit就是发生异常时执行的流程,这就是我开头说的“会有2个流程存在“。而且,从图中我们也可以看到在第13行,有一个goto指令,也就是说如果正常运行结束会跳转到19行执行。

    这下,你对synchronized是不是了解的很清晰了呢。接下来我们再聊一聊Lock。

    Lock:Lock实现和synchronized不一样,后者是一种悲观锁,它胆子很小,它很怕有人和它抢吃的,所以它每次吃东西前都把自己关起来。而Lock呢底层其实是CAS乐观锁的体现,它无所谓,别人抢了它吃的,它重新去拿吃的就好啦,所以它很乐观。具体底层怎么实现,博主不在细述,有机会的话,我会对concurrent包下面的机制好好和大家说说,如果面试问起,你就说底层主要靠volatile和CAS操作实现的。

    现在,才是我真正想在这篇博文后面加的,我要说的是:尽可能去使用synchronized而不要去使用LOCK

    什么概念呢?我和大家打个比方:你叫jdk,你生了一个孩子叫synchronized,后来呢,你领养了一个孩子叫LOCK。起初,LOCK刚来到新家的时候,它很乖,很懂事,各个方面都表现的比synchronized好。你很开心,但是你内心深处又有一点淡淡的忧伤,你不希望你自己亲生的孩子竟然还不如一个领养的孩子乖巧。这个时候,你对亲生的孩子教育更加深刻了,你想证明,你的亲生孩子synchronized并不会比领养的孩子LOCK差。(博主只是打个比方)

    那如何教育呢?
    在jdk1.6~jdk1.7的时候,也就是synchronized16、7岁的时候,你作为爸爸,你给他优化了,具体优化在哪里呢:

    1、线程自旋和适应性自旋
    我们知道,java’线程其实是映射在内核之上的,线程的挂起和恢复会极大的影响开销。并且jdk官方人员发现,很多线程在等待锁的时候,在很短的一段时间就获得了锁,所以它们在线程等待的时候,并不需要把线程挂起,而是让他无目的的循环,一般设置10次。这样就避免了线程切换的开销,极大的提升了性能。
    而适应性自旋,是赋予了自旋一种学习能力,它并不固定自旋10次一下。他可以根据它前面线程的自旋情况,从而调整它的自旋,甚至是不经过自旋而直接挂起。

    2、锁消除
    什么叫锁消除呢?就是把不必要的同步在编译阶段进行移除。
    那么有的小伙伴又迷糊了,我自己写的代码我会不知道这里要不要加锁?我加了锁就是表示这边会有同步呀?
    并不是这样,这里所说的锁消除并不一定指代是你写的代码的锁消除,我打一个比方:
    在jdk1.5以前,我们的String字符串拼接操作其实底层是StringBuffer来实现的(这个大家可以用我前面介绍的方法,写一个简单的demo,然后查看class文件中的字节码指令就清楚了),而在jdk1.5之后,那么是用StringBuilder来拼接的。我们考虑前面的情况,比如如下代码:

    String str1="qwe";
    String str2="asd";
    String str3=str1+str2;
    

    底层实现会变成这样:

    StringBuffer sb = new StringBuffer();
    sb.append("qwe");
    sb.append("asd");
    

    我们知道,StringBuffer是一个线程安全的类,也就是说两个append方法都会同步,通过指针逃逸分析(就是变量不会外泄),我们发现在这段代码并不存在线程安全问题,这个时候就会把这个同步锁消除。

    3、锁粗化
    在用synchronized的时候,我们都讲究为了避免大开销,尽量同步代码块要小。那么为什么还要加粗呢?
    我们继续以上面的字符串拼接为例,我们知道在这一段代码中,每一个append都需要同步一次,那么我可以把锁粗化到第一个append和最后一个append(这里不要去纠结前面的锁消除,我只是打个比方)

    4、轻量级锁

    5、偏向锁

    关于最后这两种,我希望留个有缘的读者自己去查找,我不希望我把一件事情描述的那么详细,自己动手得到才是你自己的,博主可以告诉你的是,最后两种并不难。。加油吧,各位。

    展开全文
  • vue---vuex全局对象的区别使用

    千次阅读 2020-03-16 13:47:30
    一、vuex全局对象的区别: 二、vue定义全局变量 三、vue定义全局方法 四、vuex使用 一、vuex全局对象的区别: 首先,来看看vuex官网对vuex全局对象两者的区别描述。 每一个 Vuex 应用的核心就是 store...

    目 录

    一、vuex与全局对象的区别:

    二、vue定义全局变量

    三、vue定义全局方法

    四、vuex使用


    一、vuex与全局对象的区别:

    首先,来看看vuex官网对vuex与全局对象两者的区别描述。

    每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:

    1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

    2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用

    (1)vuex用于做状态管理,主要是应用于vue.js中管理数据状态的一个库,通过创建一个集中的数据存储,供程序中所有组件访问,实现组件之间的传值。并且一个组件的数据变化会映射到使用这个数据的其他组件。

    (2)vuex由统一的方法修改数据,全局变量可以任意修改。

    (3)全局变量多了会造成命名污染,vuex不会,同时解决了父组件与孙组件,以及兄弟组件之间通信的问题。

    二、vue定义全局变量

    方法一:新建全局【global.js】文件,并在其中定义变量并导出,在使用的组件中引入该【global.js】文件,可为全局变量赋值(任意修改)或使用其值。

    方法二:在【main.js】中引入【global.js】:【import global from "../api/global.js";】,并通过【Vue.prototype.global=global】挂载到vue实例上,在其他组件中通过【this.global.authorization】调用。

    三、vue定义全局方法

    直接将方法写在【main.js】中,在组件中通过this.方法名 调用。

    四、vuex使用

    vuex---store状态管理

     

     

    展开全文
  • 抽象类和接口的区别使用场景

    千次阅读 多人点赞 2018-07-09 10:22:53
    抽象类和接口的区别使用场景 1.1 抽象类 1.2 接口 1.3 抽象类和接口的区别 1.3.1 语法层面上的区别 1.3.2 设计层面上的区别 1.4 什么时候使用抽象类和接口 抽象类和接口的区别使用场景 1.1 抽象类 在...

    抽象类和接口的区别及使用场景

    1.1 抽象类

    在了解抽象类之前,先来了解一下抽象方法。抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。抽象方法的声明格式为:

    abstract void fun();

    抽象方法必须用abstract关键字进行修饰。如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。

      下面要注意一个问题:在《JAVA编程思想》一书中,将抽象类定义为“包含抽象方法的类”,但是后面发现如果一个类不包含抽象方法,只是用abstract修饰的话也是抽象类。也就是说抽象类不一定必须含有抽象方法。个人觉得这个属于钻牛角尖的问题吧,因为如果一个抽象类不包含任何抽象方法,为何还要设计为抽象类?所以暂且记住这个概念吧,不必去深究为什么。

    [public] abstract class ClassName {
        abstract void fun();
    }

    从这里可以看出,抽象类就是为了继承而存在的,如果你定义了一个抽象类,却不去继承它,那么等于白白创建了这个抽象类,因为你不能用它来做任何事情。对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。

      包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别:

      1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。

      2)抽象类不能用来创建对象;

      3)如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。

      在其他方面,抽象类和普通的类并没有区别。

    1.2 接口

    接口,英文称作interface,在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到Java语言设计者的初衷,它是对行为的抽象。在Java中,定一个接口的形式如下:

    [public] interface InterfaceName {
    
    }

    接口中可以含有 变量和方法。但是要注意,接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量,用private修饰会报编译错误),而方法会被隐式地指定为public abstract方法且只能是public abstract方法(用其他关键字,比如private、protected、static、 final等修饰会报编译错误),并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法。从这里可以隐约看出接口和抽象类的区别,接口是一种极度抽象的类型,它比抽象类更加“抽象”,并且一般情况下不在接口中定义变量。
    要让一个类遵循某组特地的接口需要使用implements关键字,具体格式如下:

    class ClassName implements Interface1,Interface2,[....]{
    }

    1.3 抽象类和接口的区别

    1.3.1 语法层面上的区别

    1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
    2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
    3)抽象类可以有静态代码块和静态方法,而接口中不能含有静态代码块以及静态方法;
    4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。

    1.3.2 设计层面上的区别

    1)抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 “是不是”的关系,而 接口 实现则是 “有没有”的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。
    2)设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简单例子,大家都用过ppt里面的模板,如果用模板A设计了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对ppt B和ppt C进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。

    下面看一个网上流传最广泛的例子:门和警报的例子:门都有open( )和close( )两个动作,此时我们可以定义通过抽象类和接口来定义这个抽象概念:

    abstract class Door {
        public abstract void open();
        public abstract void close();
    }

    或者:

    interface Door {
        public abstract void open();
        public abstract void close();
    }

    但是现在如果我们需要门具有报警alarm( )的功能,那么该如何实现?下面提供两种思路:

      1)将这三个功能都放在抽象类里面,但是这样一来所有继承于这个抽象类的子类都具备了报警功能,但是有的门并不一定具备报警功能;

      2)将这三个功能都放在接口里面,需要用到报警功能的类就需要实现这个接口中的open( )和close( ),也许这个类根本就不具备open( )和close( )这两个功能,比如火灾报警器。

      从这里可以看出, Door的open() 、close()和alarm()根本就属于两个不同范畴内的行为,open()和close()属于门本身固有的行为特性,而alarm()属于延伸的附加行为。因此最好的解决办法是单独将报警设计为一个接口,包含alarm()行为,Door设计为单独的一个抽象类,包含open和close两种行为。再设计一个报警门继承Door类和实现Alarm接口。

    interface Alram {
        void alarm();
    }
    
    abstract class Door {
        void open();
        void close();
    }
    
    class AlarmDoor extends Door implements Alarm {
        void oepn() {
          //....
        }
        void close() {
          //....
        }
        void alarm() {
          //....
        }
    }

    1.4 什么时候使用抽象类和接口

    • 如果你拥有一些方法并且想让它们中的一些有默认实现,那么使用抽象类吧。
    • 如果你想实现多重继承,那么你必须使用接口。由于Java不支持多继承,子类不能够继承多个类,但可以实现多个接口。因此你就可以使用接口来解决它。
    • 如果基本功能在不断改变,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么就需要改变所有实现了该接口的类。
    展开全文
  • FPGAASIC:它们之间的区别以及使用哪一种? FPGA Vs ASIC: Differences Between Them And Which One To Use? VL82C486 Single Chip 486 System Controller ASIC. 引论 对于一个刚接触超大规模集成电路和硬件设计...

    FPGA与ASIC:它们之间的区别以及使用哪一种?

    FPGA Vs ASIC: Differences Between Them And Which One To Use?
    在这里插入图片描述
    VL82C486 Single Chip 486 System Controller ASIC.

    引论

    对于一个刚接触超大规模集成电路和硬件设计领域的人来说,这往往是第一个问题:FPGA、ASIC和CPLD之间有什么区别?在另一篇文章中,我们试图回答FPGA和CPLD之间的区别。本文将定义什么是FPGA,什么是ASIC,我们将试图阐明FPGA与ASIC的问题,并讨论它们之间的异同。我们将概述每种方法的优缺点,这样您就可以根据应用程序的需要明智地决定使用哪种方法。

    这是一个目录,你可以很容易地导航到你感兴趣的副标题。

    Content:

    · What is FPGA?

    · What is ASIC?

    · FPGA vs ASIC comparison summary

    · FPGA vs ASIC visual comparison

    · FPGA vs ASIC Cost Analysis

    · How to choose between FPGA or ASIC

    What is FPGA?

    FPGA代表现场可编程门阵列。它是一种集成电路,可以“现场”编程,按预期设计工作。这意味着它可以作为一个微处理器,或者一个加密单元,或者显卡,甚至可以同时使用这三个功能。顾名思义,FPGA是现场可编程的。因此,与半导体铸造厂不同,作为微处理器的FPGA可以重新编程,在现场充当显卡。在FPGA上运行的设计通常使用硬件描述语言(如VHDL和Verilog)创建。

    FPGA是由数千个可配置逻辑块(CLB)组成的,它们嵌入在可编程互连的海洋中。CLB主要由查找表(LUT)、多路复用器和触发器组成。它们可以实现复杂的逻辑功能。除了CLB和路由互连,许多FPGA还包含用于各种功能的专用硬硅块,如块RAM、DSP块、外部存储器控制器、PLL,千兆位收发器等。最近的一个趋势是在同一个FPGA芯片内部提供一个硬硅处理器核心(如Xilinx Zynq中的ARM Cortex A9),这样处理器就可以处理日常的、非关键的任务,而FPGA可以处理用处理器无法完成的高速加速。这些专用的硬件块在与asic竞争中至关重要。

    What is ASIC?

    ASIC代表专用集成电路。顾名思义,asic是特定于应用程序的。它们的设计目的只有一个,它们的整个使用寿命都是一样的。例如,手机内部的CPU是一个ASIC。它的功能是作为一个CPU的整个生命周期。它的逻辑功能不能改变成其他任何东西,因为它的数字电路是由永久连接的门和硅触发器组成的。ASIC的逻辑功能以类似于FPGA的方式指定,使用硬件描述语言,如Verilog或VHDL。在这种情况下,集成电路的集成电路的数量是可配置的。作为比较,可以考虑使用乐高积木建造城堡与使用混凝土建造城堡。前者类似于FPGA,而后者类似于ASIC。你可以重复使用乐高积木创造一个不同的设计,但混凝土城堡是永久性的。

    FPGA vs ASIC comparison summary

    FPGA ASIC编号

    1.FPGA可重构电路。FPGA可以用不同的设计进行重新配置。他们甚至有能力重新配置芯片的一部分,而芯片的其余部分仍在工作!这个特性被广泛应用于数据中心的加速计算。

    ASIC永久电路。一旦特定于应用的电路用胶带固定在硅上,它就不能改变。电路在其整个工作寿命内也将同样工作。

    2.FPGA设计通常使用硬件描述语言(HDL),如VHDL或Verilog。

    ASIC与FPGA相同。使用Verilog、VHDL等HDL指定设计。

    3.FPGA更容易进入障碍物。从FPGA开发开始,成本低至30美元。

    ASIC从成本、学习曲线、与半导体制造厂的联络等方面来看,进入门槛非常高。从头开始ASIC开发可能会花费数百万美元。

    4.FPGA不适合大批量生产。ASIC适合大批量生产。

    5.FPGA低能量效率,同样的功能需要更多的功率。

    ASIC可以在较低的功率下实现。比FPGA更省电。ASIC的功耗可以非常精确地控制和优化。

    6.FPGA与同类工艺节点的专用集成电路相比,工作频率有限。布线和可配置逻辑占用了FPGA的时序裕度。

    ASIC由于电路针对其特定功能进行了优化,使用同一工艺节点制造的ASIC可以比FPGA工作频率高得多。

    7.FPGA不可能进行模拟设计。例如,可编程逻辑控制器(FPC)可与模拟收发器(例如,可编程逻辑控制器(PLC)等)一样。

    ASIC在专用于模拟收发器的射频(RF)核心上,可以不包含许多专用的模拟收发器。这是FPGA所缺乏的优势。

    8.FPGA非常适合于雷达、手机基站等应用,当前的设计可能需要升级以使用更好的算法或更好的设计。在这些应用中,FPGA的高成本并不是决定因素。

    ASIC相反,可编程性是决定因素,asic绝对不适合设计可能需要频繁或偶尔升级的应用领域。

    9.FPGA优先用于原型设计和验证设计或概念。许多ASIC都是用FPGA自己设计原型的!主要处理器制造商自己使用FPGA来验证他们的片上系统(SOC)。使用FPGA原型设计更容易确保设计按预期正确工作。

    ASIC除非经过绝对验证,否则不建议使用ASIC对设计进行原型设计。一旦硅被贴上胶带,几乎什么也无法修复设计缺陷(例外情况也适用)。

    10.FPGA设计人员一般不需要关心后端设计。所有的事情都由合成和路由工具来处理,这些工具确保设计工作如RTL代码中所述,并符合时间安排。因此,设计人员可以专注于完成RTL设计。

    ASIC设计人员需要关心从RTL到重置树、时钟树、物理布局和布线、工艺节点、制造约束(DFM)、测试约束(DFT)等所有事情。通常,所述的每一个领域都由不同的专业人员处理。

    FPGA vs ASIC visual comparison
    在这里插入图片描述
    在这里插入图片描述
    根据Xilinx,ASIC vs FPGA成本分析图如上图所示。由于成本和单位价值随使用的工艺技术和时间的不同而有所不同,因此在图表中省略了成本和单位价值。ASIC有非常高的非重复性工程(NRE)成本,以百万计,而实际的每个模具成本可能是美分。就FPGA而言,不存在NRE成本。你要为实际的FPGA芯片付费,一般情况下,你可以免费获得该FPGA的软件(最高限额)。因此,由于非重复性成本的存在,ASICs的总成本开始非常高,但其斜率更平坦。也就是说,小批量的原型化asic非常昂贵,但是在大批量生产中,每版的成本变得非常低。在FPGA的情况下,IC成本相当高,因此在大批量生产中,与ASIC相比,成本变得更高。

    以下是ASIC成本构成的明细:

    1. ASIC EDA tools and training

    2. Cost of designing

    3. DFT cost

    4. Cost of simulating

    5. ASIC Masks Cost

    6. Wafer Cost

    7. Wafer Processing

    8. Die Utilization

    9. Yield & Manufacturing Loss

    10. Packaging

    与上表相比,FPGA的成本仅限于可以现货购买的IC。

    How to choose between FPGA or ASIC

    你想了解更多关于VLSI的硬件设计的人?那么FPGA和仿真软件最适合您。你在设计自己的产品吗?酷!问问自己目标市场是什么,预期的价格范围,功率预算,速度要求等等。能用FPGA实现吗?如果是的话,那就继续把你的想法原型化。如果没有,你可能没有其他办法,除了去ASIC。在大多数情况下,至少可以使用FPGA制作原型并验证您的想法。当你完成原型的时候,你自己就会知道你是否需要使用ASIC路由。当然,如果您的设计完全是突破性的,并且非常特殊,有着非常具体的要求(在成本、功率、速度等方面),那么您除了使用ASIC线路外别无选择。否则,FPGA可以满足大多数用例,特别是当您需要可重新配置的硬件时。

    展开全文
  • hive在创建表时默认存储格式是...但是却说不清楚这三种格式的干什么用的,本质有有什么区别?适合什么时候用? 因为hive是文本批处理系统,所以就存在一个往hive中导入数据的问题,首先数据的存储格式有多种,甚...
  • list并行操作在项目开发可以极大提高代码效率性能,java8对其进行了很好的封装,简单使用研究一下: 1. 先自己创建一个list: // list在实际使用中要注意线程安全,Collections.synchronizedList写操作性能高,...
  • remem的使用区别详解

    万次阅读 2018-07-01 16:56:17
    原文链接:《综合指南: 何时使用 Em Rem》你可能已经很熟练使用这两个灵活的单位,但你可能不完全了解何时使用 rem ,何时使用 em。 本教程将帮你弄清楚!Em 和 rem都是灵活、 可扩展的单位,由浏览器转换为像素值...
  • 传统关系数据库不同的是,每个 NoSQL 文档的架构是不同的,可让您更加灵活整理和存储应用程序数据并减少可选值所需的存储。 1)对应的nosql:CouchDB, MongoDb 2)典型应用场景:存储类似JSON格式的内容,可...
  • 浅论定点DSP浮点DSP的区别

    万次阅读 2018-04-02 20:43:54
    这两者有什么区别呢?于是专门查找并总结了一些资料,如下: 一般来说,定点DSP处理器具有速度快,功耗低,价格便宜的特点;而浮点DSP处理器则计算精确,动态范围大,速度快,易于编程,功耗大,价格高。 1、宏观...
  • git中使用https和ssh的区别

    千次阅读 2018-07-15 17:24:18
    clone项目:使用ssh方式时,首先你必须是该项目的管理者或拥有者,并且需要配置个人的ssh key下。意思就是使用SSH协议作为传输协议时,服务器无法提供匿名访问。也就是说,进行clone之前必须先通过认证,把你本地访问...
  • 数据库系统和文件系统的区别与联系

    万次阅读 多人点赞 2019-04-23 22:03:30
    写在前面  数据库系统DBS(Data Base System,简称DBS)通常由软件、数据库和数据管理员组成。...具体说,它负责为用户建立文件,存入、读出、修改、转储文件,控制文件的存取,当用户不再使用时撤销文件等。
  • ping 和 tracert命令的使用区别

    万次阅读 2019-04-28 08:54:51
    ping和tracert使用方法都一样,在命令后面加IP地址或者域名。 ping 主要是用来查看到目的地址的时延和丢包情况, tracert是用来查看所经过的每一跳路由,可以具体判断时延变大或者丢包的点 当ping查网站时发现...
  • super,this的区别使用

    千次阅读 2016-03-25 22:28:06
    this的使用和说明java的this关键字只能用于方法体内,java虚拟机(JVM)会给这个对象分配一个引用自身的指针,这个指针的名字就是this.注意:函数参数或者函数中的局部变量和成员变量同名的话,成员变量被屏蔽,此时要...
  • Git,GitHubGitLab的区别

    千次阅读 多人点赞 2019-09-26 20:10:50
    )是一个开源的分布式版本控制系统,可以有效、高速处理从很小到非常大的项目版本管理。Git 是 [Linus Torvalds](https://baike.baidu.com/item/Linus Torvalds/9336769) 为了帮助管理 Linux 内核开发而开发的一个...
  • Vector和ArrayList在使用上非常相似,都可用来表示一组数量可变的对象应用的集合,并且可以随机访问其中的元素。 1 Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于...
  • AIDLBinderMessenger的使用区别

    千次阅读 2016-03-10 00:05:07
    只有当你需要来自不同应用的客户端通过IPC(进程间通信)通信来访问你的服务时,并且想在服务里处理多线程的业务,这时就需要使用AIDL。 b.如果你不需要同时对几个应用进程IPC操作,你最好通过实现Binder接口来...
  • MicrobitArduino的区别

    千次阅读 2019-04-23 15:15:56
    MicrobitArduino的区别解析Microbit和Arduino的区别介绍Microbit并说明其功能。测试摇骰子,显示1-6的数字,当按下按钮b时就清空点阵灯。请使用Microbit实时测量温度的Python代码microbit支持哪些编程工具?说出优...
  • Java中notify和notifyAll的区别 - 何时以及如何使用

    万次阅读 多人点赞 2018-07-13 18:24:34
    用Java通知vs notifyAllnotify和notifyAll方法之间有什么区别是棘手的Java问题之一,这很容易回答但是一旦访问者提出后续问题,你要么感到困惑,要么无法...顺便说一句,这是你在各地阅读的内容,坦率说,这句话...
  • 在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,而当程序需要将一些数据保存起来的时候,就要使用输出流完成。 InputStream 和OutputStream,两个是为字节流设计...
  • ETLELT的区别与联系?

    千次阅读 2019-05-27 18:21:29
    ETLELT的区别与联系 其实数据集成不算一个很新的概念,可能20年前就有数据集成的工具,大家经常会使用Talent, Informatica, Kettle, Data Stage这样一些工具。这些工具有一个共性,就是它的数据计算和转化功能是...
  • 1、OutputStream,OutputStreamWriter,BufferedWriter区别 1.1、OutputStream:表示输出字节流所有类的超类。输出流接受输出字节并将它们发送到某个接收器。一般我们使用它的子类,如FileOutputStream等. 1.2、...
  • 属性字段的区别

    千次阅读 2018-08-04 20:53:18
    属性字段的区别 从两者的声明上来看,公共字段只是类用public修饰符所公开的简单公共变量,而属性则是对字段的封装,它使用get和set访问器来控制如何设置或返回字段值。 由于属性的实质是方法(get或set方法),...
  • 一文读懂机器学习深度学习的联系与区别   https://mp.weixin.qq.com/s/6Zk5JxBUs_Op1wwiY4EIZA     翻译: Tocy, kevinlinkai, 雪落无痕xdj, ZICK_ZEON, lnovonl, fozz  来源: 开源中国 链接: ...
  • mangodbmysql的区别

    千次阅读 2018-11-01 20:57:01
    查询语句是使用传统的sql语句,拥有较为成熟的体系,成熟度很高。开源数据库的份额在不断增加,mysql的份额页在持续增长。&nbsp;&nbsp; 缺点:在海量数据处理的时候效率会显著变慢。Mongodb是非关系型数据库...
  • URI和URL的区别比较理解

    万次阅读 多人点赞 2018-06-04 10:12:03
     三、URI和URL之间的区别 从上面的例子来看,你可能觉得URI和URL可能是相同的概念,其实并不是,URI和URL都定义了资源是什么,但URL还定义了该如何访问资源。URL是一种具体的URI,它是URI的一个子集,它不仅唯一...
  • 字符流字节流的区别

    万次阅读 多人点赞 2019-03-25 14:03:47
    字符流字节流的区别 (尊重劳动成果,转载请注明出处:https://blog.csdn.net/cynhafa/article/details/6882061陈江玉的博客) 字节流和字符流的使用非常相似,两者除了操作代码上的不同之外,是否还有其他的...
  • 验证(Verification)确认(Validation)的区别 验证:我们正确构造了产品吗?(注重过程-由QA负责) 确认:我们构造了正确的产品吗?(注重结果-由QC负责) 说法一: (2)“验证(Verification)”的涵义 通过...
  • RS232 RS485的区别总结

    万次阅读 多人点赞 2018-09-18 09:20:28
    简单说就是所有相等的数经过某种排序方法后,仍能保持它们在排序之前的相对次序,我们就 说这种排序方法是稳定的。反之,就是非稳定的。 比如:一组数排序前是a1,a2,a3,a4,a5,其中a2=a4,经过某种排序后为a1,a2...
  • 直流有刷电机无刷电机的区别

    万次阅读 多人点赞 2019-03-21 11:16:51
    首先介绍有刷电机无刷电机工作原理,最后从调速方式及性能差异这两个方面详细的阐述了有刷电机无刷电机的区别。  有刷电机无刷电机工作原理  1、有刷电机  电机工作时,线圈和换向器旋转,磁钢和碳刷...
  • root用户和sudo使用root权限的区别

    万次阅读 2017-03-09 21:46:53
    sudo指令-功能: 以root的身分执行命令 -语法: sudo 其他指令 -用户: 被root加入『/etc/sudoers』文件中的用户...2.把所有可执行sudo指令的用户都规范在『/etc/sudoers』这个文件中,root可以很容易掌控整个系统

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,261,184
精华内容 504,473
关键字:

地与的区别使用