精华内容
下载资源
问答
  • 同步类容器和并发类容器

    万次阅读 多人点赞 2019-07-31 19:22:20
    在Java的集合容器框架中,主要四大类别:List、Set、Queue、Map。 注意Collection和Map是顶层接口,而List、Set、Queue接口则分别继承了Collection接口,分别代表数组、集合和队列这三大类容器。 像ArrayList、...

    一.为什么会出现同步容器?

    在Java的集合容器框架中,主要有四大类别:List、Set、Queue、Map。

    注意Collection和Map是顶层接口,而List、Set、Queue接口则分别继承了Collection接口,分别代表数组、集合和队列这三大类容器。

    像ArrayList、LinkedList都是实现了List接口,HashSet实现了Set接口,而Deque(双向队列,允许在队首、队尾进行入队和出队操作)继承了Queue接口,PriorityQueue实现了Queue接口。另外LinkedList(实际上是双向链表)同时也实现了Deque接口。

    但以上容器都是非线程安全的。如果有多个线程并发地访问这些容器时,就会出现问题。因此,在编写程序时,必须要求程序员手动地在访问到这些容器的地方进行同步处理,这样导致在使用这些容器的时候非常地不方便。所以,Java提供了同步容器供用户使用。

    二.Java中的同步类容器

    在Java中,同步容器主要包括2类:

      1)Vector、Stack、HashTable

      2)Collections类中提供的静态工厂方法创建的类

    Vector实现了List接口,Vector实际上就是一个数组,和ArrayList类似,但是Vector中的方法都是synchronized方法,即进行了同步措施;Stack也是一个同步容器,它的方法也用synchronized进行了同步,它实际上是继承于Vector类;HashTable实现了Map接口,它和HashMap很相似,但是HashTable进行了同步处理,而HashMap没有。

    Collections类是一个工具提供类,注意,它和Collection不同,Collection是一个顶层的接口。在Collections类中提供了大量的方法,比如对集合或者容器进行排序、查找等操作。最重要的是,在它里面提供了几个静态工厂方法来创建同步容器类,如下图所示:

    这些同步容器都是通过synchronized进行同步来实现线程安全的,那么很显然,这必然会影响到执行性能。

    而且虽然他们都是线程安全的,但这并不说明在任何情况下都可以线程安全,看你怎么用了,例如下面的这个例子:

    public class Test {
        static Vector<Integer> vector = new Vector<Integer>();
        public static void main(String[] args) throws InterruptedException {
            while(true) {
                for(int i=0;i<10;i++)
                    vector.add(i);
                Thread thread1 = new Thread(){
                    public void run() {
                        for(int i=0;i<vector.size();i++)
                            vector.remove(i);
                    };
                };
                Thread thread2 = new Thread(){
                    public void run() {
                        for(int i=0;i<vector.size();i++)
                            vector.get(i);
                    };
                };
                thread1.start();
                thread2.start();
                while(Thread.activeCount()>10)   {
                     
                }
            }
        }
    }

    运行结果是在执行过程中会出现数组下标越界的运行时异常。也许有朋友会问:Vector是线程安全的,为什么还会报这个错?很简单,对于Vector,虽然能保证每一个时刻只能有一个线程访问它,但是不排除这种可能,当某个线程在某个时刻执行这句时:

    for(int i=0;i<vector.size();i++)

         vector.get(i);

    假若此时vector的size方法返回的是10,i的值为9,在他要获取下标为9的元素时,有另外一个线程先执行了这句:

    for(int i=0;i<vector.size();i++)

         vector.remove(i);

    将下标为9的元素删除了,在删除过程中因为有锁,所以之前的那个线程无法执行vector.get(i);处于阻塞状态,等这个线程把下标为9的元素删除了之后获取到锁再执行。那么通过get方法访问下标为9的元素肯定就会出问题了。说明这是程序逻辑本身存在线程安全问题,因此为了保证线程安全,必须在方法调用端做额外的同步措施,如下面所示:

    public class Test {
        static Vector<Integer> vector = new Vector<Integer>();
        public static void main(String[] args) throws InterruptedException {
            while(true) {
                for(int i=0;i<10;i++)
                    vector.add(i);
                Thread thread1 = new Thread(){
                    public void run() {
                        synchronized (Test.class) {   //进行额外的同步
                            for(int i=0;i<vector.size();i++)
                                vector.remove(i);
                        }
                    };
                };
                Thread thread2 = new Thread(){
                    public void run() {
                        synchronized (Test.class) {
                            for(int i=0;i<vector.size();i++)
                                vector.get(i);
                        }
                    };
                };
                thread1.start();
                thread2.start();
                while(Thread.activeCount()>10)   {
                     
                }
            }
        }
    }

    三.Java中的并发类容器

    为了解决同步类容器的性能问题,在Java 1.5之后提供了并发容器,位于java.util.concurrent目录下,这个目录俗称并发包。

    3.1、ConcurrentMap

    ConcurrentMap接口下有两个重要的实现:ConcurrentHashMap、ConcurrentSkipListMap。ConcurrentHashMap把整个哈希表分成多个segment,每个segment一把锁,主要通过锁分段技术减小了锁的粒度,降低了冲突,从而提高了并发性。在实际的应用中,散列表一般是读多写少。ConcurrentHashMap 就针对读操作做了大量的优化,运用了很多并发技巧,如不可变对象和使用volatile保证内存可见性,这样,在大多数情况下读操作甚至无需加锁也能获得正确的值。ConcurrentHashMap的concurrencyLevel(默认值为16)表示并发级别,这个值用来确定Segment的个数,Segment的个数是大于等于concurrencyLevel的第一个2的n次方的数。比如,如果concurrencyLevel为12,13,14,15,16这些数,则Segment的数目为16(2的4次方)。理想情况下ConcurrentHashMap的真正的并发访问量能够达到concurrencyLevel,因为有concurrencyLevel个Segment,假如有concurrencyLevel个线程需要访问Map,并且需要访问的数据都恰好分别落在不同的Segment中,则这些线程能够无竞争地自由访问(因为他们不需要竞争同一把锁),达到同时访问的效果。这也是为什么这个参数起名为“并发级别”的原因。该值设置过高会照成空间的浪费,设置过低会降低并发性。这种对调优的把握是要通过对底层实现的深刻理解和不断的实践积累才能获取的。

    3.2、CopyOnWirte容器

    Cope-On-Write简称COW,是一种用于程序设计中的优化策略,称为写时复制,理解起来很简单,就是执行修改操作时进行底层数组复制,使得修改操作在新的数组上进行,不妨碍原数组的并发读操作,复制修改完成后把原数组引用指向新数组。这样做的好处是可以并发的读而不需要加锁,因为当前容器不会添加任何元素,所以也是一种读写分离的思想。但正是因为写时复制,所以不能保证数据的实时性,而只能保证最终一致性。

    在concurrent包下实现CopyOnWrite机制的容器有两种,CopyOnWriteArrayList和CopyOnWriteArraySet。

    CopyOnWriteArrayList中有一个Object数组array用来存放数据,对于set()、add()、remove()等修改数据的操作会加上重入锁ReentrantLock,等修改操作完成替换掉array的引用之后才释放锁,从而保证写操作的线程安全,而针对读操作没有任何锁。

    CopyOnWriteArraySet其实就是一个CopyOnWriteArrayList,不过就是在方法中避免重复数据而已,甚至这些避免重复数据的函数也是在CopyOnWriteArrayList中定义的,CopyOnWriteArraySet中只是包含一个CopyOnWriteArrayList的属性,然后在方法上做个包装,除了equals方法外,其他当前类中的所有函数都是调用的CopyOnWriteArrayList的方法,所以严格来讲可以使用一个CopyOnWriteArrayList作为具有Set特性的写时复制数组(不过就是没有继承AbstractSet)。

    根据CopyOnWirte容器的实现原理可知,CopyOnWirte容器保证读写分离,十分适合读多写少的场景,但不适合写多的场景。

    3.3、线程安全队列

    在并发编程中我们有时候需要使用线程安全的队列。如果我们要实现一个线程安全的队列有两种实现方式一种是使用阻塞算法,另一种是使用非阻塞算法。使用阻塞算法的队列可以用一个锁(入队和出队用同一把锁)或两个锁(入队和出队用不同的锁)等方式来实现,而非阻塞的实现方式则可以使用循环CAS的方式来实现。java.util.concurrent.atomic包相关类就是CAS的实现。

    ConcurrentLinkedQueue是一个适用于高并发场景下的非阻塞的队列,通过无锁的方式(采用CAS操作),实现了高并发状态下的高性能,通常ConcurrentLinkedQueue的性能优于BlockingQueue。ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部,当我们获取一个元素时,它会返回队列头部的元素,该队列不允许NULL元素。

    阻塞队列当队列是空的时候,再想获取元素就会阻塞进入等待状态,所以非常适合生产者-消费者模式。阻塞队列BlockingQueue接口JDK提供了7种实现:

    • ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
    • LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
    • PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
    • DelayQueue:一个使用优先级队列实现的无界阻塞队列。
    • SynchronousQueue:一个不存储元素的阻塞队列。
    • LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
    • LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
    展开全文
  • 使用Spring上下文获取容器内对象

    千次阅读 2018-08-23 13:38:04
    前者的作用在于让spring容器来管理这个类,而后者的作用就是从spring容器中获取这个类的对象,更关键的是,这个对象是单例的。 为了使用@Autowired获取某个类的单例,必须将当前类也交给spring容器管理,即使用@...

    在spring应用中,经常使用@Component、@Controller、@Service注解,与之匹配的还有一个更加常见的@Autowired注解。前者的作用在于让spring容器来管理这个类,而后者的作用就是从spring容器中获取这个类的对象,更关键的是,这个对象是单例的。

    为了使用@Autowired获取某个类的单例,必须将当前类也交给spring容器管理,即使用@Component等注解标识这个类。但是这样会出现一个问题,就是当前类的调用也必须通过注解来获得。那么,new就无法使用了。举个例子,我有一个TaskThread类,每次发布任务时就会启动了一个TaskThread类,这里必须通过new来实例化对象,但是TaskThread类中又需要用到service层、dao层的对象,而在这时候这些对象是不能被@Autowired的,因为这样做没有效果,所有的@Autowired对象都会是null。那么应该怎么办呢?

    通过spring上下文来获取单例对象的实例!
    一种简单的获取spring上下文的方式是通过spring启动类来获取,下面看实现:

    // spring应用启动类
    @SpringBootApplication
    public class WebTestApplication extends SpringBootServletInitializer {
    
    
      public static void main(String[] args) {
        //SpringApplication.run(WebTestApplication.class, args);
        SystemVariable.context = SpringApplication.run(WebTestApplication.class, args);
      }
    
      @Override
      protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(WebTestApplication.class);
      }
    }
    
    // 系统变量类,存储了spring上下文
    public class SystemVariable {
      public static ConfigurableApplicationContext context; // spring上下文
    }
    
    // 线程类,使用spring上下文获取bean单例
    public class TaskThread extends Thread{
    
        private TaskService taskService;
        private CommentDAO commentDAO;
        
        public TaskThread() {
          taskService = SystemVariable.getBean(TaskService.class);
          commentDAO = SystemVariable.getBean(CommentDAO.class);
            
        }
        @Override
        public void run(){
            
        }
    }
    

    补充:还可以通过spring上下文获取系统配置变量,就像是@Value("${}")一样。如下:

    String recSMSEnable = SystemVariable.context.getEnvironment().getProperty("recSMSEnable");
    // 这里的recSMSEnable是位于springboot配置文件application.yml里面的一个配置信息
    
    展开全文
  • spring 获取容器容器中的对象

    千次阅读 2018-09-07 16:04:41
    当启动服务(springboot、tomcat)之后多已经配置(注解、xml配置)对象将会实例化,最后放入到ApplicationContext里面,这里提供一种spingcloud 启动时可以查看的部分伪代码: public class TestA...

    spring容器中获取已注入对象的几种方式:
    首先理解spring容器中是谁负责装载这些对象:ApplicationContext,对是它;
    当启动服务(springboot、tomcat)之后所有已经配置(注解、xml配置)对象将会实例化,最后放入到ApplicationContext里面,这里提供一种spingcloud 启动时可以查看的部分伪代码
    public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
    
    @Bean
    public CommandLineRunner appRuner(ApplicationContext ac) {
        return args -> {
           Object user= ac.getBean("user");
           //通过类名(BeanName)获取已注入对象,这里user是一个被注入到容器中的Bean==》User类;
            System.out.println(user);
            String[] names = ac.getBeanDefinitionNames();
           for (int i = 0; i < names.length; i++) {
                System.out.println(names[i]);//可以看到每个BeanName,但首字母是小写的
            }
        };
    }
    

    }

    获取spring的容器ApplicationContext几种方式【转】

    展开全文
  •  子容器可以获取父容器的bean对象,父容器不可获取子容器的bean。 注意了这里仅是bean,对于一些属性文件 @value("${key}"),子容器也是拿到父容器的。--------------------以下是现象---------------...

         我们知道spring中,有spring的容器为父容器,springmvc的容器为子容器。

       子容器可以获取父容器的bean对象,父容器不可获取子容器的bean

       注意了这里仅是bean,对于一些属性文件 @value("${key}"),子容器也是拿不到父容器的。

    --------------------以下是现象-----------------------------------------

     1.sc-custom.properties属性文件


    2.springmvc中加载属性文件

    3.controller中


    访问(可以拿到值):

    -------------子容器去拿到父容器的属性配置------------------

    1.springmvc 加载属性文件去掉


    2.spring中有相应配置


    3.访问:



      正好遇到记录下来。

    网友相关(侵删):

    https://blog.csdn.net/qq_25868207/article/details/70885387

    https://blog.csdn.net/qq_40369829/article/details/80023745


    展开全文
  • 写代码碰到一个这样的情况,在一个没有...然后我们会想到new 一个ApplicationContext对象,再从他里面取,其实这样不是一个有效的解决办法,因为你根本知道存放在容器中的对象有多少,如果很多,构造一个Application
  • SpringBoot 从容器中获取对象

    千次阅读 2018-08-04 17:05:53
    SpringBoot 从容器中获取对象 代码很简单 @Component public class SpringUtil implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void ...
  • Java容器可以说是增强程序员编程...如果对象的数量与生命周期都是固定的,自然我们也就需要很复杂的数据结构。 我们可以通过创建引用来持有对象,如 Class clazz; 也可以通过数组来持有多个对象,如 Class[...
  • vector容器存入类对象写法

    千次阅读 2017-04-25 09:53:22
    声明一个Aclass 类,然后用容器vector存该类的对象 通常恰当的写法如下 class Aclass{/**/}; vector ac; /*   operations...  */ Aclass a_obj; vector::iterator i = find(ac.begin(), ac....
  • spring容器创建对象的时机

    千次阅读 2015-09-10 15:12:26
    在spring基础(一)中,我们谈到了spring容器创建对象的三种方式,现在我们来谈一下spring容器创建对象的时机:那么,我们如何判断一个对象是在spring容器启动的时候创建的呢 还是在我们调用这个对象的时候创建的?...
  • SpringIOC容器 1) 创建对象 SpringIOC容器,是spring核心内容。...创建对象, 几种方式: 1) 调用无参数构造器 2) 带参数构造器 3) 工厂创建对象 工厂类,静态方法创建对象 工厂类,非静态方法创建对象
  • 断言判断数组、对象容器相等

    千次阅读 2018-11-17 20:16:44
    在使用Junit进行单元测试时,时候会遇到测试方法返回数组、对象容器的情况,这时候该如何判断测试的期望值与实际值是否相等呢?
  • 每次压入新对象的时候,都会与容器中所有存在的老对象进行比较,当新对象的hashCode 与equals,与容器中已经存在的任何一个老对象相同时,就认为两个对象时相同的,就用新对象替换掉老对象 package df.util....
  • java 容器哪些?

    万次阅读 多人点赞 2019-07-27 18:36:57
    容器可以说是Java Core中比较重要的一部分了。 数组,String,java.util下的集合容器 ============================================================================== 数组长度限制为 Integer.Integer.MAX_...
  •   Spring中的容器对象接口是ApplicationContext,其作用就是加载配置文件,并初始化所有的Bean对象(容器启动时)。其实现类主要2个,分别为: ClassPathXmlApplicationContext:加载类路径下的Spring配置...
  • SpringUtil获取Spring容器对象

    千次阅读 2018-11-02 19:15:51
    自己公司使用的简单的SpringUtil,可以使用直接从Spring容器中获取对象.比较方便. 主要就是实现ApplicationContextAware ,学过Spring的都知道,Spring提供一些实现Aware对应的类,来获取对应的信息,比如,...
  • 无法枚举容器中的对象,访问被拒绝的解决方法
  • 我们时候也会遇到一些脱离spring容器创建的类实例,如何把spring容器内对象注入到这些类实例呢。  我们可以用org.springframework.beans.factory.config.AutowireCapableBeanFactory.createBean(Class bean...
  • 最近项目中就有如题的一个需求,有些对象希望将其交给spring容器去管理,想通过自己new的方式去实例化,以便自己更好的去维护这个对象。 这里非SPRING管理的对象,即自己实例化的对象,用A来代替,SPRING管理的...
  • servlet容器,web容器,spring容器,springmvc容器的区别

    千次阅读 多人点赞 2019-05-03 21:42:40
    web容器servlet容器,spring项目部署后存在spring容器和springmvc容器。其中spring控制service层和dao层的bean对象。springmvc容器控制controller层bean对象。servlet容器控制servlet对象。项目启动是,首先 ...
  • spring容器创建对象的生命周期

    千次阅读 2015-09-10 17:43:14
    前面我们提到了,IOC的概念:把对象的创建、初始化、销毁等工作交给spring容器来完成。对象的创建我们在前面几个例子已经讨论到了,现在,我们来讨论一下对象的初始化,销毁对象的初始化和销毁,也是spring来完成...
  • 获取Spring容器对象

    万次阅读 2010-09-12 17:13:00
    众所周知,Spring框架将DI模式...但是,对于系统中非Spring框架管理的类,如果需要获取Spring管理的类,或者,程序中需要动态的根据Bean的id来获取Bean实例,可能事先为该类提供所有需要的Bean属性的setter方法,在
  • Spring 容器对象创建的过程

    千次阅读 2018-06-13 23:57:02
    Spring容器负责对象的创建过程,配置并且管理他们的创建过程,从创建到被回收。Spring多种容器的实现,分为两种类型,bean工厂,最简单的容器,提供DI的支持。应用上下文是基于beanFactory构建的,提供企业极的...
  • Flex中改变对象容器中的叠放层次

    千次阅读 2014-11-25 19:22:58
    关键字: flex中改变对象在容器中的叠放层次1、在容器中添加对象、移除对象和检测容器中是否存在对象 容器对象.addChild(显示对象);//在容器中添加对象 容器对象.removeChild(显示对象);//在容器中删除对象 容器...
  • STL容器里存放对象还是指针

    千次阅读 2013-04-13 11:24:05
    一.问题的引出: 容器可以存放对象,可以存放指针,这里要...对于建类型(int float char等),容器的工作方式是纯粹的位拷贝,这里没有什么需要多说的。 对于自定义的对象容器容纳了对象(比如通过insert或pu
  • 一直以为spring的ioc容器生成的对象都是代理对象,其实这个是错误的。spring ioc默认的都是原生对象 只有通过aop增强的对象才是代理对象有@Transactional 注解或者配置文件&lt;aop:config&gt; &lt;...
  • spring IOC容器创建对象的三种方式

    千次阅读 2017-02-26 12:13:59
    SpringIOC容器,是spring核心内容。 作用:创建对象 & 处理对象的...创建对象, 三种方式: 1) 调用无参数构造器 2) 带参数构造器 3) 工厂创建对象  工厂类,静态方法创建对象  工厂类,非静态方法创建对象
  • java中容器Vectort用add添加对象对象引用的问题  众所周知的是在java中去掉了c++中的最为神奇的指针,但是java中存在着引用(个人认为java中的引用与c++的指针很相似,只是不能如指针那般使用)。引用,我们可以...
  • Java容器有哪些?哪些是同步容器,哪些是并发容器? 一、基本概念 容器集 同步容器 并发容器 二、Collection集合接口 List接口 LinkedList类 ArrayList类 Vector类 Stack类 Set接口 HashSet类 TreeSet 三、Map集合...
  • Java-通过工厂、Map容器创建对象

    千次阅读 多人点赞 2021-03-28 10:28:30
    本文通过两种方式去创建对象,1.工厂+反射+配置文件:单例模式,每次调用工厂方法都会创建一个对象。 第二种对一做了一个优化,当类加载时,对象就已经构造好,之后每次使用从map中获取就行。其实Spring IOC做的就是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 879,866
精华内容 351,946
关键字:

容器内不能有容器对象