精华内容
下载资源
问答
  • JDK1.8 创建线程池几种方式

    万次阅读 多人点赞 2019-05-16 12:48:53
    JDK1.8创建线程池几种方式? newFixedThreadPool 定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程 测试代码...

    JDK1.8 创建线程池有哪几种方式?

    • newFixedThreadPool

    定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程

    测试代码:

    public class TestThreadPool {
    
    	//定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程
    	static ExecutorService fixedExecutor = Executors.newFixedThreadPool(3);
    	
    	
    	public static void main(String[] args) {
    		testFixedExecutor();
    	}
    	
    	//测试定长线程池,线程池的容量为3,提交6个任务,根据打印结果可以看出先执行前3个任务,3个任务结束后再执行后面的任务
    	private static void testFixedExecutor() {
    		for (int i = 0; i < 6; i++) {
    			final int index = i;
    			fixedExecutor.execute(new Runnable() {
    				public void run() {
    					try {
    						Thread.sleep(3000);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println(Thread.currentThread().getName() + " index:" + index);
    				}
    			});
    		}
    		
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("4秒后...");
    		
    		fixedExecutor.shutdown();
    	}
    	
    }

    打印结果:

    pool-1-thread-1 index:0
    pool-1-thread-2 index:1
    pool-1-thread-3 index:2
    4秒后...
    pool-1-thread-3 index:5
    pool-1-thread-1 index:3
    pool-1-thread-2 index:4

     

     

    • newCachedThreadPool

    可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制

    测试代码:  

    public class TestThreadPool {
    
    	//可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制
    	static ExecutorService cachedExecutor = Executors.newCachedThreadPool();
    	
    	
    	public static void main(String[] args) {
    		testCachedExecutor();
    	}
    	
    	//测试可缓存线程池
    	private static void testCachedExecutor() {
    		for (int i = 0; i < 6; i++) {
    			final int index = i;
    			cachedExecutor.execute(new Runnable() {
    				public void run() {
    					try {
    						Thread.sleep(3000);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println(Thread.currentThread().getName() + " index:" + index);
    				}
    			});
    		}
    		
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("4秒后...");
    		
    		cachedExecutor.shutdown();
    	}
    	
    }
    

    打印结果:

    pool-1-thread-1 index:0
    pool-1-thread-6 index:5
    pool-1-thread-5 index:4
    pool-1-thread-4 index:3
    pool-1-thread-3 index:2
    pool-1-thread-2 index:1
    4秒后...
    

     

     

    • newScheduledThreadPool

    定长线程池,可执行周期性的任务

    测试代码:

    public class TestThreadPool {
    
    	//定长线程池,可执行周期性的任务
    	static ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(3);
    	
    	
    	public static void main(String[] args) {
    		testScheduledExecutor();
    	}
    	
    	//测试定长、可周期执行的线程池
    	private static void testScheduledExecutor() {
    		for (int i = 0; i < 3; i++) {
    			final int index = i;
    			//scheduleWithFixedDelay 固定的延迟时间执行任务; scheduleAtFixedRate 固定的频率执行任务
    			scheduledExecutor.scheduleWithFixedDelay(new Runnable() {
    				public void run() {
    					System.out.println(Thread.currentThread().getName() + " index:" + index);
    				}
    			}, 0, 3, TimeUnit.SECONDS);
    		}
    		
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("4秒后...");
    		
    		scheduledExecutor.shutdown();
    	}
    	
    }

    打印结果:

    pool-1-thread-1 index:0
    pool-1-thread-2 index:1
    pool-1-thread-3 index:2
    pool-1-thread-1 index:0
    pool-1-thread-3 index:1
    pool-1-thread-1 index:2
    4秒后...
    

     

     

    • newSingleThreadExecutor

    单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行

    测试代码:

    public class TestThreadPool {
    	
    	//单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行
    	static ExecutorService singleExecutor = Executors.newSingleThreadExecutor();
    	
    	
    	public static void main(String[] args) {
    		testSingleExecutor();
    	}
    	
    	//测试单线程的线程池
    	private static void testSingleExecutor() {
    		for (int i = 0; i < 3; i++) {
    			final int index = i;
    			singleExecutor.execute(new Runnable() {
    				public void run() {
    					try {
    						Thread.sleep(3000);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println(Thread.currentThread().getName() + " index:" + index);
    				}
    			});
    		}
    		
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("4秒后...");
    		
    		singleExecutor.shutdown();
    	}
    	
    }
    

    打印结果:

    pool-1-thread-1 index:0
    4秒后...
    pool-1-thread-1 index:1
    pool-1-thread-1 index:2

     

     

    • newSingleThreadScheduledExecutor

    单线程可执行周期性任务的线程池

    测试代码:

    public class TestThreadPool {
    	
    	//单线程可执行周期性任务的线程池
    	static ScheduledExecutorService singleScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
    	
    	
    	public static void main(String[] args) {
    		testSingleScheduledExecutor();
    	}
    	
    	//测试单线程可周期执行的线程池
    	private static void testSingleScheduledExecutor() {
    		for (int i = 0; i < 3; i++) {
    			final int index = i;
    			//scheduleWithFixedDelay 固定的延迟时间执行任务; scheduleAtFixedRate 固定的频率执行任务
    			singleScheduledExecutor.scheduleAtFixedRate(new Runnable() {
    				public void run() {
    					System.out.println(Thread.currentThread().getName() + " index:" + index);
    				}
    			}, 0, 3, TimeUnit.SECONDS);
    		}
    		
    		try {
    			Thread.sleep(4000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("4秒后...");
    		
    		singleScheduledExecutor.shutdown();
    	}
    	
    }

    打印结果:

    pool-1-thread-1 index:0
    pool-1-thread-1 index:1
    pool-1-thread-1 index:2
    pool-1-thread-1 index:0
    pool-1-thread-1 index:1
    pool-1-thread-1 index:2
    4秒后...
    

     

     

    • newWorkStealingPool

    任务窃取线程池,不保证执行顺序,适合任务耗时差异较大。

    线程池中有多个线程队列,有的线程队列中有大量的比较耗时的任务堆积,而有的线程队列却是空的,就存在有的线程处于饥饿状态,当一个线程处于饥饿状态时,它就会去其它的线程队列中窃取任务。解决饥饿导致的效率问题。

    默认创建的并行 level 是 CPU 的核数。主线程结束,即使线程池有任务也会立即停止。

    测试代码:

    public class TestThreadPool {
    
    	//任务窃取线程池
    	static ExecutorService workStealingExecutor = Executors.newWorkStealingPool();
    	
    	public static void main(String[] args) {
    		testWorkStealingExecutor();
    	}
    	
    	//测试任务窃取线程池
    	private static void testWorkStealingExecutor() {
    		for (int i = 0; i < 10; i++) {//本机 CPU 8核,这里创建10个任务进行测试
    			final int index = i;
    			workStealingExecutor.execute(new Runnable() {
    				public void run() {
    					try {
    						Thread.sleep(3000);
    					} catch (InterruptedException e) {
    						e.printStackTrace();
    					}
    					System.out.println(Thread.currentThread().getName() + " index:" + index);
    				}
    			});
    		}
    		
    		try {
    			Thread.sleep(4000);//这里主线程不休眠,不会有打印输出
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		System.out.println("4秒后...");
    		
    //		workStealingExecutor.shutdown();
    	}
    	
    }

    打印结果如下,index:8,index:9并未打印出:

    ForkJoinPool-1-worker-1 index:0
    ForkJoinPool-1-worker-7 index:6
    ForkJoinPool-1-worker-5 index:4
    ForkJoinPool-1-worker-3 index:2
    ForkJoinPool-1-worker-4 index:3
    ForkJoinPool-1-worker-2 index:1
    ForkJoinPool-1-worker-0 index:7
    ForkJoinPool-1-worker-6 index:5
    4秒后...
    

     


    【Java面试题与答案】整理推荐

     

    展开全文
  • 这是最新的大厂面试系列,还原真实场景,提炼出知识点分享给大家。 点赞再看,养成习惯~ 微信搜索【武哥聊编程】,关注这个 Java 菜鸟。...Java 创建线程种方式: 继承Thread,并重写run(...

    这是最新的大厂面试系列,还原真实场景,提炼出知识点分享给大家。
    点赞再看,养成习惯~ 微信搜索【武哥聊编程】,关注这个 Java 菜鸟。

    昨天有个小伙伴去阿里面试实习生岗位,面试官问他了一个老生常谈的问题:你说一说 Java 创建线程都有哪些方式?

    这哥们心中窃喜,这个老生常谈的问题早已背的滚瓜烂熟,于是很流利的说了出来。

    Java 创建线程有两种方式:

    1. 继承Thread类,并重写run()方法
    2. 实现Runnable接口,覆盖接口中的run()方法,并把Runnable接口的实现扔给Thread

    面试官:(拿出一张白纸)那你把这两种方式写一下吧!

    小哥:(这有何难!)好~

    public static void main(String[] args) {
    	// 第一种
        MyThread myThread = new MyThread();
        myThread.start();
    	// 第二种
        new Thread(() -> System.out.println("自己实现的run-2")).start();
    }
    
    public static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("自己实现的run-1");
        }
    }
    

    面试官:嗯,那除了这两种,还有其他创建线程的方法吗?

    这些简单的问题难不倒这哥们,于是他想到了 Java5 之后的ExecutorsExecutors工具类可以用来创建线程池。

    小哥:Executors工具类是用来创建线程池的,这个线程池可以指定线程个数,也可以不指定,也可以指定定时器的线程池,它有如下常用的方法:

    newFixedThreadPool(int nThreads):创建固定数量的线程池
    newCachedThreadPool():创建缓存线程池
    newSingleThreadExecutor():创建单个线程
    newScheduledThreadPool(int corePoolSize):创建定时器线程池

    面试官:嗯,OK,咱们还是针对你刚刚写的代码,我再问你个问题。

    此时这哥们有种不祥的预感,是不是自己代码写的有点问题?或者要问我底层实现?

    面试官:你写的两种创建线程的方式,都涉及到了run()方法,你了解过Thread里的run()方法具体是怎么实现的吗?

    果然问到了源码了,这哥们之前看了点,所以不是很慌,回忆了一下,向面试官道来。

    小哥:emm……Thread 中的run()方法里东西很少,就一个 if 判断:

    @Override
    public void run() {
    	if (target != null) {
    		target.run();
    	}
    }
    

    有个target对象,会去判断该变量是否为空,非空的时候,去执行target对象中的run()方法,否则啥也不干。而这个target对象,就是我们说的Runnable

    /* What will be run. */
    private Runnable target;
    

    面试官:嗯,那这个Runnable类你了解过吗?
    小哥:了解过,这个Runnable类很简单,就一个抽象方法:

    @FunctionalInterface
    public interface Runnable {
        public abstract void run();
    }
    

    这个抽象方法也是run()!如果我们使用Runnable接口,就需要实现这个run()方法。由于这个Runnable类上面标了@FunctionalInterface注解,所以可以使用函数式编程。

    那小哥接着说:(突然自信起来了)所以这就对应了刚才说的两种创建线程的方式,假如我用第一种方式:继承了Thread类,然后重写了run()方法,那么它就不会去执行上面这个默认的run()方法了(即不会去判断target),会执行我重写的run()方法逻辑。

    假如我是用的第二种方式:实现Runnable接口的方式,那么它会执行默认的run()方法,然后判断target不为空,再去执行我在Runnable接口中实现的run()方法。

    面试官:OK,可以,我再问你个问题。

    小哥:(暗自窃喜)

    面试官:那如果我既继承了Thread类,同时我又实现了Runnable接口,比如这样,最后会打印什么信息出来呢?

    面试官边说边拿起刚刚这小哥写的代码,对它进行了简单的修改:

    public static void main(String[] args) {
        new Thread(() -> System.out.println("runnable run")) {
            @Override
            public void run() {
                System.out.println("Thread run");
            }
        }.start();
    }
    

    这小哥,突然有点懵,好像从来没想过这个问题,一时没有什么思路,于是回答了个:会打印 “Thread run” 吧……

    面试官:答案是对的,但是为什么呢?

    这小哥一时没想到原因,于是面试官让他回去可以思考思考,就继续下一个问题了。

    亲爱的读者朋友,你们知道为什么吗?你们可以先思考一下。

    其实这个答案很简单,我们来分析一下代码便知:其实是 new 了一个对象(子对象)继承了Thread对象(父对象),在子对象里重写了父类的run()方法;然后父对象里面扔了个Runnable进去,父对象中的run()方法就是最初那个带有 if 判断的run()方法。

    好了,现在执行start()后,肯定先在子类中找run()方法,找到了,父类的run()方法自然就被干掉了,所以会打印出:Thread run。

    如果我们现在假设子类中没有重写run()方法,那么必然要去父类找run()方法,父类的run()方法中就得判断是否有Runnable传进来,现在有一个,所以执行Runnable中的run()方法,那么就会打印:Runnable run 出来。

    说白了,就是问了个 Java 语言本身的父子继承关系,会优先执行子类重写的方法而已,只是借这个场景,换了个提问的方式,面试者可能一时没反应过来,有点懵也是正常的,如果直接问,傻子都能回答的出来。

    后记:通过这道简单的面试题,帮大家分析了一下在创建线程过程中的源码,可以看出来,面试过程中,面试官更加看重一些原理性的东西,而不是背一下方式就行了。同时也能看的出,面试大厂,需要做好充分的准备。另外,在面试的时候要冷静,可能有些问题并没有太难,回答不出来只是当时太紧张造成的。

    这篇文章就写到这,最后祝大家都能面试成功。

    如果觉得有帮助,希望老铁们来个三连击,给更多的人看到这篇文章

    1、关注我的原创微信公众号「武哥聊编程」,专注于Java、数据结构和算法、微服务、中间件等技术分享,保证你看完有所收获。

    2、给俺点个赞呗,可以让更多的人看到这篇文章,顺便激励下我继续写作,嘻嘻。

    作者info

    【作者】:武哥
    【公众号】:武哥聊编程。欢迎大家关注~
    【作者简介】:同济大学,硕士。先后在华为、科大讯飞、拼多多采坑。一个自学 Java 的菜鸟,期待你的关注。

    点赞是对我最大的鼓励
    ↓↓↓↓↓↓

    展开全文
  • 创建线程池几种方式

    千次阅读 2020-05-04 22:15:27
    创建线程池几种方式一、Executors二、ThreadPoolExecutor 一、Executors Executors是一个线程相关的工具。主要提供了以下几种创建线程池的方法: index method corePoolSize maximumPoolSize ...

    一、Executors

    Executors是一个线程相关的工具类。主要提供了以下几种创建线程池的方法:

    indexmethodcorePoolSizemaximumPoolSizekeepAliveTimeunitworkQueue
    1newCachedThreadPool0Integer.MAX_VALUE60LTimeUnit.SECONDSSynchronousQueue
    2newFixedThreadPool自定义与corePoolSize相同0LTimeUnit.MILLISECONDSLinkedBlockingQueue
    3newSingleThreadExecutor110LTimeUnit.MILLISECONDSLinkedBlockingQueue
    4newScheduledThreadPool自定义Integer.MAX_VALUE0NANOSECONDSDelayedWorkQueue
    5newSingleThreadScheduledExecutor1Integer.MAX_VALUE0NANOSECONDSDelayedWorkQueue

    第1,4,5种:线程最大数量是Integer.MAX_VALUE,当执行大量耗时任务时,容易造成堆外内存溢出
    第2,3种:使用的的阻塞队列为无边界队列,当任务量过大时,可能会导致内存溢出

    注意: 在java8中新添加了newWorkStealingPool

    二、ThreadPoolExecutor

    ThreadPoolExecutor(int corePoolSize, //核心线程数量
                       int maximumPoolSize, // 最大线程数量
                       long keepAliveTime, // 存活时间 
                       TimeUnit unit, // 时间单位
                       BlockingQueue<Runnable> workQueue, //阻塞队列
                       ThreadFactory threadFactory) // 拒绝策略
    

    注意: 有多于corePoolSize但小于maximumPoolSize线程正在运行,则仅当队列已满时才会创建新线程

    在这里插入图片描述

    展开全文
  • Spring:创建Bean的几种方式

    万次阅读 多人点赞 2016-06-04 17:42:21
    Spring创建工厂的三种方式

    Spring支持如下三种方式创建Bean

    1:调用构造器创建Bean

    2:调用静态工厂方法创建Bean

    3:调用实例工厂方法创建Bean

    一:调用构造方法创建Bean

      调用构造方法创建Bean是最常用的一种情况Spring容器通过new关键字调用构造器来创建Bean实例,通过class属性指定Bean实例的实现类,也就是说,如果使用构造器创建Bean方法,则<bean/>元素必须指定class属性,其实Spring容器也就是相当于通过实现类new了一个Bean实例。调用构造方法创建Bean实例,通过名字也可以看出,我们需要为该Bean类提供无参数的构造器。下面是一个通过构造方法创建Bean的最简单实例

    1:Bean实例实现类 Person.java

    package com.mao.gouzao;
    
    public class Person 
    {
    	private String name;
    
    	public Person() 
    	{
    		System.out.println("Spring容器开始通过无参构造器创建Bean实例------------");
    	}
    	//Spring容器通过setter方法为参数注入值
    	public void setName(String name) 
    	{
    		this.name = name;
    	}
    	public void input()
    	{
    		System.out.println("欢迎来到我的博客:"+name);
    	}
    
    }
    

    因为是通过构造函数创建Bean,因此我们需要提供无参数构造函数,另外我们定义了一个name属性,并提供了setter方法,Spring容器通过该方法为name属性注入参数。

    2:配置文件beans.xml

    <?xml version="1.0" encoding="GBK"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns="http://www.springframework.org/schema/beans"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans
    	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    	<!-- 指定class属性,通过构造方法创建Bean实例 -->
    	<bean id="person" class="com.mao.gouzao.Person">
    	  <!-- 通过调用setName方法,将VipMao作为参数传入 -->
    	  <property name="name" value="VipMao"></property>
    	</bean>
    </beans>
    配置文件中,通过<bean>元素的id属性指定该bean的唯一名称,class属性指定该bean的实现类,可以理解成Spring容器就是通过该实现类new了一个Bean。通过<property>标签的name属性和value属性指定了:调用setName方法,将VipMao作为参数注入。

    3:测试类 PersonTest.java

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class PersonTest 
    {
    	public static void main(String[]args)
    	{
    		//创建Spring容器
    		ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
    		//通过getBean()方法获取Bean实例
    		Person person=(Person) ctx.getBean("person");
    		person.input();
    	}
    }
    

    4:运行结果


    二:调用静态工厂方法创建Bean

      通过静态工厂创建Bean,是不是听着高大上了?顾名思义,咱们把创建Bean的任务交给了静态工厂,而不是构造函数,这个静态工厂就是一个Java类,那么使用静态工厂创建Bean咱们又需要添加哪些属性呢?我们同样需要在<bean/>元素内添加class属性,上面也说了,静态工厂是一个Java类,那么该class属性指定的就是该工厂的实现类,而不再是Bean的实现类,告诉Spring这个Bean应该由哪个静态工厂创建,另外我们还需要添加factory-method属性来指定由工厂的哪个方法来创建Bean实例,因此使用静态工厂方法创建Bean实例需要为<bean/>元素指定如下属性:
    class:指定静态工厂的实现类,告诉Spring该Bean实例应该由哪个静态工厂创建(指定工厂地址)
    factory-method:指定由静态工厂的哪个方法创建该Bean实例(指定由工厂的哪个车间创建Bean)
    如果静态工厂方法需要参数,则使用<constructor-arg.../>元素传入
    下面是一个简单的通过静态工厂方法创建Bean

    1:首先我们定义一个Person的接口,定义一个说话的方法say()。 Person.java

    package com.mao.staticFactory;
    
    public interface Person 
    {
    	public void say();
    }
    
    在程序中,我们尽量将一些特殊方法抽象出来定义成接口,在后面的程序中需要此方法,或者说具备此功能的时候,咱们直接实现该接口,以面向接口的方式完成某些功能。

    2:Chinese Bean实现类Chinese.java

    package com.mao.staticFactory;
    
    public class Chinese implements Person
    {
    	private String msg;
    	//提供setter方法
    	public void setMsg(String msg) 
    	{
    		this.msg = msg;
    	}
    	@Override
    	public void say() 
    	{
    		// TODO Auto-generated method stub
    		System.out.println(msg+",打倒一切美帝国主义");
    	}
    
    }
    
    Chinese类实现了Person接口,完成了方法的实现,并定义了一个msg属性,提供了相应的setter方法,Spring通过该方法完成msg属性的参数值注入。

    3:American Bean实现类American.java

    package com.mao.staticFactory;
    
    public class American implements Person
    {
    	private String msg;
    	//提供setter方法
    	public void setMsg(String msg) 
    	{
    		this.msg = msg;
    	}
    	@Override
    	public void say() 
    	{
    		// TODO Auto-generated method stub
    		System.out.println(msg+",我要重返亚太地区");
    	}
    	
    }
    

    与Chinese Bean实例没太大的区别,

    4:重点来了 配置文件 beans.xml

    <?xml version="1.0" encoding="GBK"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns="http://www.springframework.org/schema/beans"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans
    	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
            <!-- 定义chinese Bean 由PersonFactory工厂的getPerson方法创建 -->
    	<bean id="chinese" class="com.mao.staticFactory.PersonFactory" factory-method="getPerson">
    	  <!-- 为静态工厂的getPerson()方法传参 -->
    	  <constructor-arg value="chinese"/>
    	  <!-- 调用setMsg()方法为msg属性注入参数值 -->
    	  <property name="msg" value="我是中国人"/>
    	</bean>	
    	<!-- 创建american Bean -->
    	<bean id="american" class="com.mao.staticFactory.PersonFactory" factory-method="getPerson">
    	  <constructor-arg value="american"/>
    	  <property name="msg" value="我是美国人"></property>
           </bean>
    </beans>
    拿chinese Bean来讲,配置文件中,通过<bean>元素的 class属性指定了,静态工厂的实现类,通过factory-method指定由静态工厂的哪个方法创建,也就是通过PersonFactory这个静态工厂的getPerson()方法创建,并且通过<constructor-arg.../>元素为该方法传入了一个chinese的参数。

    5:静态工厂 PersonFactory.java

    package com.mao.staticFactory;
    
    public class PersonFactory {
    	public static Person getPerson(String arg)
    	{
    	if(arg.equalsIgnoreCase("chinese"))
    	{
    		return new Chinese();
    	}	
    	else
    	{
    		return new American();
    	}
      }
    }
    
    静态工厂类的getPerson()方法就是通过咱们传入的相应参数来创建相应的Bean实体,然后返回相应实体。

    6:主函数测试类 PersonTest.java

    package com.mao.staticFactory;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class PersonTest 
    {
    	public static void main(String []args)
    	{
    		//创建容器
    		ApplicationContext ctx=new ClassPathXmlApplicationContext("beans.xml");
    		//获取相应实体
    		Chinese c=(Chinese) ctx.getBean("chinese" , Person.class);
    		c.say();
    		American a=(American) ctx.getBean("american" , Person.class);
    		a.say();
    	}
    }
    

    7:运行结果:



    三:调用实例工厂方法创建Bean

      首先咱们再顾名思义一下哈,静态工厂通过class指定静态工厂实现类然后通过相应的方法创建即可,调用实例工厂则需要先创建该工厂的Bean实例,然后引用该实例工厂Bean的id创建其他Bean,在实例工厂中通过factory-bean指定工厂Bean的实例,在调用实例化工厂方法中,不用在<bean/>中指定class属性,因为这时,咱们不用直接实例化该Bean,而是通过调用实例化工厂的方法,创建Bean实例,调用实例化工厂需要为<bean/>指定一下两个属性
    factory-bean :该属性指定工厂Bean的id
    factory-method:该属性指定实例工厂的工厂方法。
    下面是我们将上面调用静态方法的例子稍微改一下

    仅需将配置文件beans.xml修改为:

    <?xml version="1.0" encoding="GBK"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns="http://www.springframework.org/schema/beans"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans
    	http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
            <!-- 配置工厂Bean,class指定该工厂的实现类,该Bean负责产生其他Bean实例 -->
    	<bean id="personFactory" class="com.mao.instanceFactory.PersonFactory"/>
    	<!-- 由实例工厂Bean的getPerson()方法,创建Chinese Bean, -->
    	<bean id="ch" factory-bean="personFactory" factory-method="getPerson">
    	  <!-- 为该方法传入参数为chinese -->
    	  <constructor-arg value="chinese"/>
    	</bean>
    	<!-- 由实例工厂Bean的getPerson()方法,创建American Bean, -->
    	<bean id="usa" factory-bean="personFactory" factory-method="getPerson">
    	  <constructor-arg value="american"></constructor-arg>
    	</bean>
    </beans>
    

    运行结果是一样的:


    调用实例工厂创建Bean和调用静态工厂的区别

       其实调用实例工厂创建Bean和调用静态工厂创建Bean的区别就在于,调用实例工厂将工厂单独拿了出来(先实例化工厂)创建一个工厂Bean,通过工厂<bean>的class属性指定工厂的实现类,然后再需要创建其他Bean时,只需要在该<bean/>元素添加factory-bean、factory-method指定该Bean是有哪个实例工厂的哪个方法创建就可以了,放在现实生活中就是:我们先找一个地方创建一个工厂,id指定工厂注册名字(xxx有限公司),class指定公司所在地,工厂里面有车间(创造其他Bean的方法),那好有了工厂我们再需要创建其他Bean时,只需要指定这个Bean是由,哪个工厂的哪个车间创建的即可,也就是 只需要在该<bean/>元素添加factory-bean、factory-method属性即可




    展开全文
  • java中创建对象的几种方式

    千次阅读 2017-06-26 15:58:42
    创建对象的几种方式
  • Java 创建对象的几种方式

    万次阅读 2017-02-22 17:09:52
    我们总是讨论没有对象就去new一个对象,创建对象的方式在我这里...这里就总结一下创建对象的几种方式,来好好学习一下java创建对象的方式。一、使用new关键字这是我们最常见的也是最简单的创建对象的方式,通过这种方式
  • 线程创建的四种方式

    万次阅读 多人点赞 2018-03-30 14:34:14
    Java可以用四种方式创建线程,如下所示: 1)继承Thread类创建线程 2)实现Runnable接口创建线程 3)使用Callable和Future创建线程 4)使用线程池例如用Executor框架 下面让我们分别来看看这四种创建线程的...
  • java创建对象的几种方式

    千次阅读 2018-09-17 16:57:17
    最简单最常用的创建对象方式,包括无参的和参的构造函数。 例如: 通过NEW关键字创建方式: Test test = new Test();//通过无参构造函数创建 Test test1 = new Test(this);//this表示上下...
  • Spring创建对象的几种方式

    千次阅读 2018-03-26 11:04:59
    Spring的核心思想是IOC,即所有对象的创建都是...Spring创建对象以下几种方式: 无参构造器 参构造器 工厂模式 静态方法 非静态方法 构造器创建对象 applicationContext.xml &lt;beans xmlns="...
  • 创建对象的几种方式

    千次阅读 2017-04-11 18:25:20
    在javascript中,所有对象的创建都是基于原型的。在js中任意的对象都一个内部属性[[Prototype]]。这个属性的值只能是object或者是null。对象这个内部属性的目的就是为了实现继承,或者更明确的说实现属性(方法...
  • 【JAVA】创建对象的几种方式

    千次阅读 2018-09-14 20:07:51
    创建对象的几种方式 在java中,万事万物皆对象,作为开发者,我们每天也会创建大量的对象。那么你知道几种创建对象的方式吗? 一、使用new关键字 Student student=new Student(); 这种方式是我们最熟知的方式...
  • Java中创建对象的几种方式

    千次阅读 2017-05-19 10:10:00
    然后究竟多少种创建对象的方法呢? 这里列举一下:使用New关键字、使用Class的newInstance方法、使用Constructor的newInstance方法、使用Clone方法、使用反序列化。 new关键字 这是最简单最常用的创建对象...
  • 创建线程的几种方式
  • java8 Stream-创建流的几种方式

    万次阅读 多人点赞 2018-06-09 17:00:13
    前面(《java8 Stream接口简介》),我们已经对stream这个接口,做了简单的介绍,下面,我们用几个案例,来看看流的几种创建方式 String[] dd = { "a", "b", "c" }; Arrays.stream(dd).forEach(System.out::...
  • java创建线程的三种方式: 继承Thread类创建线程 通过Runable接口创建线程 通过Callable和FutureTask创建线程 总结下: 实现Runnable和实现Callable接口的方式基本相同,不过是后者执行call()方法返回值。 1...
  • JAVA创建对象几种方式

    千次阅读 2015-06-09 17:11:59
    4显式地创建对象的方式: 1.用new语句创建对象,这是最常用的创建对象的方式。 2.运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor的newInstance()实例方法。 3.调用对象的clone...
  • 利用反射创建对象的几种方式

    千次阅读 2019-05-23 15:50:42
    1.使用Class对象的newInstance()方法来创建类的实例,这种方式要求该Class对象的对应类默认构造器,执行newInstance()实际上是利用默认构造器来创建该类的实例。 2.先使用Class对象获取到Constructor对象,在调用...
  • 创建线程几种方式?3种

    千次阅读 2020-07-20 08:17:10
    1.继承Thread类型重写run 方法 public class ... System.out.println("通过继承Thread重写run方法实现接口!"); } public static void main(String[] args) { ThreadDemoTest threadDemoTest = new T
  • js创建自定义对象的几种方式

    千次阅读 2017-08-27 17:26:26
    js创建对象的几种方式
  • 详解Java创建线程的几种方式

    千次阅读 2017-10-19 20:14:30
    在Java线程中,以下三种方式可以实现线程的创建。 通过继承Thread,调用Thread的start方法实现线程的创建 实现Runnable接口 实现Callable接口 继承Thread可以实现线程的创建,但当我们需要继承其他父类的时候...
  • Pytorch中创建Tensor的几种方式详解

    万次阅读 多人点赞 2019-07-31 23:44:45
    tensor是Pytorch中数据的基础单元,那么如何创建tensor,pytorch中提供了以下四种方式: torch.Tensor() torch.tensor() torch.as_tensor() torch.from_numpy() 那么这四种创建tensor的方式有什么区别呢,在具体...
  • java 创建线程的三种方式创建线程池的四种方式

    万次阅读 多人点赞 2019-02-23 21:01:44
    java创建线程的三种方式: 继承Thread类创建线程 实现Runnable接口 通过Callable和Future创建线程 java创建线程池的四种方式: newCachedThreadPool 创建一个可缓存的线程池,如果线程池长度超过处理...
  • Java创建数组的几种方式

    万次阅读 多人点赞 2016-01-20 23:59:56
    1、一维数组的声明方式: type[] arrayName; 或 type arrayName[];...建议不要使用第二种方式 下面是典型的声明数组的方式:  // 声明整型数组  int[] intArray0 ;  int intArray1 [];  /
  • Executors创建线程池的几种方式

    千次阅读 2019-07-03 11:02:10
    让我们再看看Executors提供的那个工厂方法。 阿里发布的 Java开发手册中强制线程池不允许使用 Executors 去创建。 newSingleThreadExecutor 创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当...
  • Java创建对象的几种方式

    千次阅读 2014-05-14 20:43:39
    Java创建有种方式: (1)用new 语句创建对象,这是最常用的创建对象方法。 (2)运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor的newInstance()实例方法。 (3)调用对象的clone()...
  • 创建并启动线程几种方式

    千次阅读 2017-12-14 23:26:12
    一:创建线程的几种方式 1.第一种方法是将声明为 Thread 的子类。该子类应重写 Thread 的 run 方法,然后在run方法里填写相应的逻辑代码。class ThreadDemo1 extends Thread{ @Override public void run() {...
  • 创建线程有几种不同的方式

    千次阅读 2017-04-20 10:45:26
    ①继承Thread(真正意义上的线程),是Runnable接口的实现。 ②实现Runnable接口,并重写里面的run方法。 ③使用Executor框架创建线程池。Executor框架是juc里提供的线程池的实现。 调用线程的start():启动...
  • 12.创建线程有几种不同的方式?你喜欢哪一种?为什么?    种方式可以用来创建线程:    继承 Thread 实现 Runnable 接口 应用程序可以使用 Executor 框架来创建线程池 实现 Runnable 接口这种方式更受...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,057,517
精华内容 423,006
关键字:

创建类有几种方式