一个通用并发对象池的实现

原文链接译文链接,原文作者: Sarma Swaranga,本文最早发表于deepinmind,校对:郑旭东

这篇文章里我们主要讨论下如何在Java里实现一个对象池。最近几年,Java虚拟机的性能在各方面都得到了极大的提升,因此对大多数对象而言,已经没有必要通过对象池来提高性能了。根本的原因是,创建一个新的对象的开销已经不像过去那样昂贵了。

然而,还是有些对象,它们的创建开销是非常大的,比如线程,数据库连接等这些非轻量级的对象。在任何一个应用程序里面,我们肯定会用到不止一个这样的对象。如果有一种很方便的创建管理这些对象的池,使得这些对象能够动态的重用,而客户端代码也不用关心它们的生命周期,还是会很给力的。

在真正开始写代码前,我们先来梳理下一个对象池需要完成哪些功能。

  • 如果有可用的对象,对象池应当能返回给客户端。
  • 客户端把对象放回池里后,可以对这些对象进行重用。
  • 对象池能够创建新的对象来满足客户端不断增长的需求。
  • 需要有一个正确关闭池的机制来确保关闭后不会发生内存泄露。

不用说了,上面几点就是我们要暴露给客户端的连接池的接口的基本功能。

我们的声明的接口如下:


01 package com.test.pool;
02 
03/**
04  * Represents a cached pool of objects.
05  *
06  * @author Swaranga
07  *
08  * @param <T> the type of object to pool.
09  */
10 public interface Pool<T>
11{
12  /**
13   * Returns an instance from the pool.
14   * The call may be a blocking one or a non-blocking one
15   * and that is determined by the internal implementation.
16   *
17   * If the call is a blocking call,
18   * the call returns immediately with a valid object
19   * if available, else the thread is made to wait
20   * until an object becomes available.
21   * In case of a blocking call,
22   * it is advised that clients react
23   * to {@link InterruptedException} which might be thrown
24   * when the thread waits for an object to become available.
25   *
26   * If the call is a non-blocking one,
27   * the call returns immediately irrespective of
28   * whether an object is available or not.
29   * If any object is available the call returns it
30   * else the call returns < code >null< /code >.
31   *
32   * The validity of the objects are determined using the
33   * {@link Validator} interface, such that
34   * an object < code >o< /code > is valid if
35   * < code > Validator.isValid(o) == true < /code >.
36   *
37   * @return T one of the pooled objects.
38   */
39  T get();
40 
41  /**
42   * Releases the object and puts it back to the pool.
43   *
44   * The mechanism of putting the object back to the pool is
45   * generally asynchronous,
46   * however future implementations might differ.
47   *
48   * @param t the object to return to the pool
49   */
50 
51  void release(T t);
52 
53  /**
54   * Shuts down the pool. In essence this call will not
55   * accept any more requests
56   * and will release all resources.
57   * Releasing resources are done
58   * via the < code >invalidate()< /code >
59   * method of the {@link Validator} interface.
60   */
61 
62  void shutdown();
63}

为了能够支持任意对象,上面这个接口故意设计得很简单通用。它提供了从池里获取/返回对象的方法,还有一个关闭池的机制,以便释放对象。

现在我们来实现一下这个接口。开始动手之前,值得一提的是,一个理想的release方法应该先尝试检查下这个客户端返回的对象是否还能重复使用。如果是的话再把它扔回池里,如果不是,就舍弃掉这个对象。我们希望这个Pool接口的所有实现都能遵循这个规则。在开始具体的实现类前,我们先创建一个抽象类,以便限制后续的实现能遵循这点。我们实现的抽象类就叫做AbstractPool,它的定义如下:


01 package com.test.pool;
02 
03/**
04  * Represents an abstract pool, that defines the procedure
05  * of returning an object to the pool.
06  *
07  * @author Swaranga
08  *
09  * @param <T> the type of pooled objects.
10  */
11 abstract class AbstractPool <T> implements Pool <T>
12{
13  /**
14   * Returns the object to the pool.
15   * The method first validates the object if it is
16   * re-usable and then puts returns it to the pool.
17   *
18   * If the object validation fails,
19   * some implementations
20   * will try to create a new one
21   * and put it into the pool; however
22   * this behaviour is subject to change
23   * from implementation to implementation
24   *
25   */
26  @Override
27  public final void release(T t)
28  {
29   if(isValid(t))
30   {
31    returnToPool(t);
32   }
33   else
34   {
35    handleInvalidReturn(t);
36   }
37  }
38 
39  protected abstract void handleInvalidReturn(T t);
40 
41  protected abstract void returnToPool(T t);
42 
43  protected abstract boolean isValid(T t);
44}

在上面这个类里,我们让对象池必须得先验证对象后才能把它放回到池里。具体的实现可以自由选择如何实现这三种方法,以便定制自己的行为。它们根据自己的逻辑来决定如何判断一个对象有效,无效的话应该怎么处理(handleInvalidReturn方法),怎么把一个有效的对象放回到池里(returnToPool方法)。

有了上面这几个类,我们就可以着手开始具体的实现了。不过还有个问题,由于上面这些类是设计成能支持通用的对象池的,因此具体的实现不知道该如何验证对象的有效性(因为对象都是泛型的)。因此我们还需要些别的东西来帮助我们完成这个。

我们需要一个通用的方法来完成对象的校验,而具体的实现不必关心对象是何种类型。因此我们引入了一个新的接口,Validator,它定义了验证对象的方法。这个接口的定义如下:


01 package com.test.pool;
02 
03  /**
04   * Represents the functionality to
05   * validate an object of the pool
06   * and to subsequently perform cleanup activities.
07   *
08   * @author Swaranga
09   *
10   * @param < T > the type of objects to validate and cleanup.
11   */
12  public static interface Validator < T >
13  {
14   /**
15    * Checks whether the object is valid.
16    *
17    * @param t the object to check.
18    *
19    * @return <code>true</code>
20    * if the object is valid else <code>false</code>.
21    */
22   public boolean isValid(T t);
23 
24   /**
25    * Performs any cleanup activities
26    * before discarding the object.
27    * For example before discarding
28    * database connection objects,
29    * the pool will want to close the connections.
30    * This is done via the
31    * <code>invalidate()</code> method.
32    *
33    * @param t the object to cleanup
34    */
35 
36   public void invalidate(T t);
37  }

上面这个接口定义了一个检验对象的方法,以及一个把对象置为无效的方法。当准备废弃一个对象并清理内存的时候,invalidate方法就派上用场了。值得注意的是这个接口本身没有任何意义,只有当它在对象池里使用的时候才有意义,所以我们把这个接口定义到Pool接口里面。这和Java集合库里的Map和Map.Entry是一样的。所以我们的Pool接口就成了这样:


01 package com.test.pool;
02 
03/**
04  * Represents a cached pool of objects.
05  *
06  * @author Swaranga
07  *
08  * @param < T > the type of object to pool.
09  */
10 public interface Pool< T >
11{
12  /**
13   * Returns an instance from the pool.
14   * The call may be a blocking one or a non-blocking one
15   * and that is determined by the internal implementation.
16   *
17   * If the call is a blocking call,
18   * the call returns immediately with a valid object
19   * if available, else the thread is made to wait
20   * until an object becomes available.
21   * In case of a blocking call,
22   * it is advised that clients react
23   * to {@link InterruptedException} which might be thrown
24   * when the thread waits for an object to become available.
25   *
26   * If the call is a non-blocking one,
27   * the call returns immediately irrespective of
28   * whether an object is available or not.
29   * If any object is available the call returns it
30   * else the call returns < code >null< /code >.
31   *
32   * The validity of the objects are determined using the
33   * {@link Validator} interface, such that
34   * an object < code >o< /code > is valid if
35   * < code > Validator.isValid(o) == true < /code >.
36   *
37   * @return T one of the pooled objects.
38   */
39  T get();
40 
41  /**
42   * Releases the object and puts it back to the pool.
43   *
44   * The mechanism of putting the object back to the pool is
45   * generally asynchronous,
46   * however future implementations might differ.
47   *
48   * @param t the object to return to the pool
49   */
50 
51  void release(T t);
52 
53  /**
54   * Shuts down the pool. In essence this call will not
55   * accept any more requests
56   * and will release all resources.
57   * Releasing resources are done
58   * via the < code >invalidate()< /code >
59   * method of the {@link Validator} interface.
60   */
61 
62  void shutdown();
63 
64  /**
65   * Represents the functionality to
66   * validate an object of the pool
67   * and to subsequently perform cleanup activities.
68   *
69   * @author Swaranga
70   *
71   * @param < T > the type of objects to validate and cleanup.
72   */
73  public static interface Validator < T >
74  {
75   /**
76    * Checks whether the object is valid.
77    *
78    * @param t the object to check.
79    *
80    * @return <code>true</code>
81    * if the object is valid else <code>false</code>.
82    */
83   public boolean isValid(T t);
84 
85   /**
86    * Performs any cleanup activities
87    * before discarding the object.
88    * For example before discarding
89    * database connection objects,
90    * the pool will want to close the connections.
91    * This is done via the
92    * <code>invalidate()</code> method.
93    *
94    * @param t the object to cleanup
95    */
96 
97   public void invalidate(T t);
98  }
99}

准备工作已经差不多了,在最后开始前我们还需要一个终极武器,这才是这个对象池的杀手锏。就是“能够创建新的对象”。我们的对象池是泛型的,因此它们得知道如何去生成新的对象来填充这个池子。这个功能不能依赖于对象池本身,必须要有一个通用的方式来创建新的对象。通过一个ObjectFactory的接口就能完成这个,它只有一个“如何创建新的对象”的方法。我们的ObjectFactory接口如下:


01 package com.test.pool;
02 
03/**
04  * Represents the mechanism to create
05  * new objects to be used in an object pool.
06  *
07  * @author Swaranga
08  *
09  * @param < T > the type of object to create.
10  */
11 public interface ObjectFactory < T >
12{
13  /**
14   * Returns a new instance of an object of type T.
15   *
16   * @return T an new instance of the object of type T
17   */
18  public abstract T createNew();
19}

我们的工具类都已经搞定了,现在可以开始真正实现我们的Pool接口了。因为我们希望这个池能在并发程序里面使用,所以我们会创建一个阻塞的对象池,当没有对象可用的时候,让客户端先阻塞住。我们的阻塞机制是让客户端一直阻塞直到有对象可用为止。这样的话导致我们还需要再增加一个只阻塞一定时间的方法,如果在超时时间到来前有对象可用则返回,如果超时了就返回null而不是一直等待下去。这样的实现有点类似Java并发库里的LinkedBlockingQueue,因此真正实现前我们再暴露一个接口,BlockingPool,类似于Java并发库里的BlockingQueue接口。

这里是BlockingQueue的声明:


01 package com.test.pool;
02 
03 import java.util.concurrent.TimeUnit;
04 
05/**
06  * Represents a pool of objects that makes the
07  * requesting threads wait if no object is available.
08  *
09  * @author Swaranga
10  *
11  * @param < T > the type of objects to pool.
12  */
13 public interface BlockingPool < T > extends Pool < T >
14{
15  /**
16   * Returns an instance of type T from the pool.
17   *
18   * The call is a blocking call,
19   * and client threads are made to wait
20   * indefinitely until an object is available.
21   * The call implements a fairness algorithm
22   * that ensures that a FCFS service is implemented.
23   *
24   * Clients are advised to react to InterruptedException.
25   * If the thread is interrupted while waiting
26   * for an object to become available,
27   * the current implementations
28   * sets the interrupted state of the thread
29   * to <code>true</code> and returns null.
30   * However this is subject to change
31   * from implementation to implementation.
32   *
33   * @return T an instance of the Object
34   * of type T from the pool.
35   */
36  T get();
37 
38  /**
39   * Returns an instance of type T from the pool,
40   * waiting up to the
41   * specified wait time if necessary
42   * for an object to become available..
43   *
44   * The call is a blocking call,
45   * and client threads are made to wait
46   * for time until an object is available
47   * or until the timeout occurs.
48   * The call implements a fairness algorithm
49   * that ensures that a FCFS service is implemented.
50   *
51   * Clients are advised to react to InterruptedException.
52   * If the thread is interrupted while waiting
53   * for an object to become available,
54   * the current implementations
55   * set the interrupted state of the thread
56   * to <code>true</code> and returns null.
57   * However this is subject to change
58   * from implementation to implementation.
59   *
60   *
61   * @param time amount of time to wait before giving up,
62   *   in units of <tt>unit</tt>
63   * @param unit a <tt>TimeUnit</tt> determining
64   *   how to interpret the
65   *        <tt>timeout</tt> parameter
66   *
67   * @return T an instance of the Object
68   * of type T from the pool.
69   *
70   * @throws InterruptedException
71   * if interrupted while waiting
72   */
73 
74  T get(long time, TimeUnit unit) throws InterruptedException;
75}

BoundedBlockingPool的实现如下:


001 package com.test.pool;
002 
003 import java.util.concurrent.BlockingQueue;
004 import java.util.concurrent.Callable;
005 import java.util.concurrent.ExecutorService;
006 import java.util.concurrent.Executors;
007 import java.util.concurrent.LinkedBlockingQueue;
008 import java.util.concurrent.TimeUnit;
009 public final class BoundedBlockingPool
010         extends <AbstractPool>
011         implements <BlockingPool>
012{
013     private int size;
014     private BlockingQueue  objects;
015     private Validator  validator;
016     private ObjectFactory  objectFactory;
017     private ExecutorService executor =
018             Executors.newCachedThreadPool();
019     private volatile boolean shutdownCalled;
020 
021     public BoundedBlockingPool(
022             int size,
023             Validator  validator,
024             ObjectFactory  objectFactory)
025     {
026         super();
027         this.objectFactory = objectFactory;
028         this.size = size;
029         this.validator = validator;
030         objects = new LinkedBlockingQueue (size);
031         initializeObjects();
032         shutdownCalled = false;
033     }
034 
035     public T get(long timeOut, TimeUnit unit)
036     {
037         if(!shutdownCalled)
038         {
039             T t = null;
040             try
041             {
042                 t = objects.poll(timeOut, unit);
043                 return t;
044             }
045             catch(InterruptedException ie)
046             {
047                 Thread.currentThread().interrupt();
048             }
049             return t;
050         }
051         throw new IllegalStateException(
052                 'Object pool is already shutdown');
053     }
054 
055     public T get()
056     {
057         if(!shutdownCalled)
058         {
059             T t = null;
060             try
061             {
062                 t = objects.take();
063             }
064 
065             catch(InterruptedException ie)
066             {
067                 Thread.currentThread().interrupt();
068             }
069             return t;
070         }
071 
072         throw new IllegalStateException(
073                 'Object pool is already shutdown');
074     }
075 
076     public void shutdown()
077     {
078         shutdownCalled = true;
079         executor.shutdownNow();
080         clearResources();
081     }
082 
083     private void clearResources()
084     {
085         for(T t : objects)
086         {
087             validator.invalidate(t);
088         }
089     }
090 
091     @Override
092     protected void returnToPool(T t)
093     {
094         if(validator.isValid(t))
095         {
096             executor.submit(new ObjectReturner(objects, t));
097         }
098     }
099 
100     @Override
101     protected void handleInvalidReturn(T t)
102     {
103     }
104 
105     @Override
106     protected boolean isValid(T t)
107     {
108         return validator.isValid(t);
109     }
110 
111     private void initializeObjects()
112     {
113         for(int i = 0; i < size; i++)
114         {
115             objects.add(objectFactory.createNew());
116         }
117     }
118 
119     private class ObjectReturner
120             implements <Callable>
121     {
122         private BlockingQueue  queue;
123         private E e;
124         public ObjectReturner(BlockingQueue  queue, E e)
125         {
126             this.queue = queue;
127             this.e = e;
128         }
129 
130         public Void call()
131         {
132             while(true)
133             {
134                 try
135                 {
136                     queue.put(e);
137                     break;
138                 }
139                 catch(InterruptedException ie)
140                 {
141                     Thread.currentThread().interrupt();
142                 }
143             }
144             return null;
145         }
146 
147     }
148 
149}

上面是一个非常基本的对象池,它内部是基于一个LinkedBlockingQueue来实现的。这里唯一比较有意思的方法就是returnToPool。因为内部的存储是一个LinkedBlockingQueue实现的,如果我们直接把返回的对象扔进去的话,如果队列已满可能会阻塞住客户端。不过我们不希望客户端因为把对象放回池里这么个普通的方法就阻塞住了。所以我们把最终将对象插入到队列里的任务作为一个异步的的任务提交给一个Executor来执行,以便让客户端线程能立即返回。

现在我们将在自己的代码中使用上面这个对象池,用它来缓存数据库连接。我们需要一个校验器来验证数据库连接是否有效。

下面是这个JDBCConnectionValidator:


01 package com.test;
02 
03 import java.sql.Connection;
04 import java.sql.SQLException;
05 import com.test.pool.Pool.Validator;
06 public final class JDBCConnectionValidator implements Validator < Connection >
07{
08     public boolean isValid(Connection con)
09     {
10         if(con == null)
11         {
12             return false;
13         }
14 
15         try
16         {
17             return !con.isClosed();
18         }
19         catch(SQLException se)
20         {
21             return false;
22         }
23 
24     }
25 
26     public void invalidate(Connection con)
27     {
28         try
29         {
30             con.close();
31         }
32         catch(SQLException se)
33         {
34         }
35     }
36 
37}

还有一个JDBCObjectFactory,它将用来生成新的数据库连接对象:


01 package com.test;
02 
03 import java.sql.Connection;
04 import java.sql.DriverManager;
05 import java.sql.SQLException;
06 import com.test.pool.ObjectFactory;
07 public class JDBCConnectionFactory implements ObjectFactory < Connection >
08{
09    private String connectionURL;
10    private String userName;
11    private String password;
12    public JDBCConnectionFactory(
13      String driver,
14      String connectionURL,
15      String userName,
16      String password) {
17      super();
18      try
19      {
20         Class.forName(driver);
21      }
22      catch(ClassNotFoundException ce)
23      {
24         throw new IllegalArgumentException('Unable to find driver in classpath', ce);
25      }
26      this.connectionURL = connectionURL;
27      this.userName = userName;
28      this.password = password;
29    }
30 
31    public Connection createNew()
32    {
33       try
34       {
35          return DriverManager.getConnection(
36             connectionURL,
37             userName,
38             password);
39       }
40       catch(SQLException se)
41       {
42          throw new IllegalArgumentException('Unable to create new connection', se);
43       }
44    }
45}

现在我们用上述的Validator和ObjectFactory来创建一个JDBC的连接池:


01 package com.test;
02 
03 import java.sql.Connection;
04 import com.test.pool.Pool;
05 import com.test.pool.PoolFactory;
06 
07 public class Main
08{
09     public static void main(String[] args)
10     {
11         Pool < Connection > pool =
12             new BoundedBlockingPool < Connection > (
13             10,
14             new JDBCConnectionValidator(),
15             new JDBCConnectionFactory('', '', '', '')
16         );
17         //do whatever you like
18     }
19}

为了犒劳下能读完整篇文章的读者,我这再提供另一个非阻塞的对象池的实现,这个实现和前面的唯一不同就是即使对象不可用,它也不会让客户端阻塞,而是直接返回null。具体的实现在这:


01 package com.test.pool;
02 
03 import java.util.LinkedList;
04 import java.util.Queue;
05 import java.util.concurrent.Semaphore;
06 
07 public class BoundedPool < T > extends AbstractPool < T >
08{
09     private int size;
10     private Queue < T > objects;
11     private Validator < T > validator;
12     private ObjectFactory < T > objectFactory;
13     private Semaphore permits;
14     private volatile boolean shutdownCalled;
15 
16     public BoundedPool(
17         int size,
18         Validator < T > validator,
19         ObjectFactory < T > objectFactory)
20         {
21         super();
22         this.objectFactory = objectFactory;
23         this.size = size;
24         this.validator = validator;
25         objects = new LinkedList < T >();
26         initializeObjects();
27         shutdownCalled = false;
28     }
29 
30     @Override
31     public T get()
32     {
33         T t = null;
34 
35         if(!shutdownCalled)
36         {
37             if(permits.tryAcquire())
38             {
39                 t = objects.poll();
40             }
41 
42          }
43          else
44          {
45              throw new IllegalStateException('Object pool already shutdown');
46          }
47          return t;
48      }
49 
50      @Override
51      public void shutdown()
52      {
53          shutdownCalled = true;
54          clearResources();
55      }
56 
57      private void clearResources()
58      {
59          for(T t : objects)
60          {
61              validator.invalidate(t);
62          }
63      }
64 
65      @Override
66      protected void returnToPool(T t)
67      {
68          boolean added = objects.add(t);
69          if(added)
70          {
71              permits.release();
72          }
73      }
74 
75      @Override
76      protected void handleInvalidReturn(T t)
77      {
78      }
79 
80      @Override
81      protected boolean isValid(T t)
82      {
83          return validator.isValid(t);
84      }
85 
86      private void initializeObjects()
87      {
88          for(int i = 0; i < size; i++)
89          {
90              objects.add(objectFactory.createNew());
91          }
92      }
93}

考虑到我们现在已经有两种实现,非常威武了,得让用户通过工厂用具体的名称来创建不同的对象池了。工厂来了:


01 package com.test.pool;
02 
03 import com.test.pool.Pool.Validator;
04 
05/**
06 
07* Factory and utility methods for
08 
09* {@link Pool} and {@link BlockingPool} classes
10 
11* defined in this package.
12* This class supports the following kinds of methods:
13*
14*
15<ul>
16*
17<li> Method that creates and returns a default non-blocking
18*        implementation of the {@link Pool} interface.
19*   </li>
20*
21*
22<li> Method that creates and returns a
23*        default implementation of
24*        the {@link BlockingPool} interface.
25*   </li>
26*
27</ul>
28*
29* @author Swaranga
30*/
31 public final class PoolFactory
32{
33     private PoolFactory()
34     {
35     }
36 
37/**
38* Creates a and returns a new object pool,
39* that is an implementation of the {@link BlockingPool},
40* whose size is limited by
41* the <tt> size </tt> parameter.
42*
43* @param size the number of objects in the pool.
44* @param factory the factory to create new objects.
45* @param validator the validator to
46* validate the re-usability of returned objects.
47*
48* @return a blocking object pool
49* bounded by <tt> size </tt>
50*/
51 public static < T > Pool < T >
52newBoundedBlockingPool(
53 int size,
54ObjectFactory < T > factory,
55Validator < T > validator)
56{
57     return new BoundedBlockingPool < T > (
58     size,
59     validator,
60     factory);
61}
62/*
63* Creates a and returns a new object pool,
64* that is an implementation of the {@link Pool}
65* whose size is limited
66* by the <tt> size </tt> parameter.
67*
68* @param size the number of objects in the pool.
69* @param factory the factory to create new objects.
70* @param validator the validator to validate
71* the re-usability of returned objects.
72*
73* @return an object pool bounded by <tt> size </tt>
74*/
75 public static < T > Pool < T > newBoundedNonBlockingPool(
76     int size,
77     ObjectFactory < T > factory,
78     Validator < T > validator)
79{
80     return new BoundedPool < T >(size, validator, factory);
81}
82}

现在我们的客户端就能用一种可读性更强的方式来创建对象池了:


01 package com.test;
02 
03 import java.sql.Connection;
04 import com.test.pool.Pool;
05 import com.test.pool.PoolFactory;
06 
07 public class Main
08{
09     public static void main(String[] args)
10     {
11         Pool < Connection > pool =
12         PoolFactory.newBoundedBlockingPool(
13         10,
14         new JDBCConnectionFactory('', '', '', ''),
15         new JDBCConnectionValidator());
16         //do whatever you like
17      }
18}

好吧,终于写完了,拖了这么久了。尽情使用和完善它吧,或者再多加几种实现。

快乐编码,快乐分享! 

内容概要:本文档详细介绍了在三台CentOS 7服务器(IP地址分别为192.168.0.157、192.168.0.158和192.168.0.159)上安装和配置Hadoop、Flink及其他大数据组件(如Hive、MySQL、Sqoop、Kafka、Zookeeper、HBase、Spark、Scala)的具体步骤。首先,文档说明了环境准备,包括配置主机名映射、SSH免密登录、JDK安装等。接着,详细描述了Hadoop集群的安装配置,包括SSH免密登录、JDK配置、Hadoop环境变量设置、HDFS和YARN配置文件修改、集群启动与测试。随后,依次介绍了MySQL、Hive、Sqoop、Kafka、Zookeeper、HBase、Spark、Scala和Flink的安装配置过程,包括解压、环境变量配置、配置文件修改、服务启动等关键步骤。最后,文档提供了每个组件的基本测试方法,确保安装成功。 适合人群:具备一定Linux基础和大数据组件基础知识的运维人员、大数据开发工程师以及系统管理员。 使用场景及目标:①为大数据平台建提供详细的安装指南,确保各组件能够顺利安装和配置;②帮助技术人员快速掌握Hadoop、Flink等大数据组件的安装与配置,提升工作效率;③适用于企业级大数据平台的建与维护,确保集群稳定运行。 其他说明:本文档不仅提供了详细的安装步骤,还涵盖了常见的配置项解释和故障排查建议。建议读者在安装过程中仔细阅读每一步骤,并根据实际情况调整配置参数。此外,文档中的命令和配置文件路径均为示例,实际操作时需根据具体环境进行适当修改。
在无线通信领域,天线阵列设计对于信号传播方向和覆盖范围的优化至关重要。本题要求设计一个广播电台的天线布局,形成特定的水平面波瓣图,即在东北方向实现最大辐射强度,在正东到正北的90°范围内辐射衰减最小且无零点;而在其余270°范围内允许出现零点,且正西和西南方向必须为零。为此,设计了一个由4个铅垂铁塔组成的阵列,各铁塔上的电流幅度相等,相位关系可自由调整,几何布置和间距不受限制。设计过程如下: 第一步:构建初级波瓣图 选取南北方向上的两个点源,间距为0.2λ(λ为电磁波波长),形成一个端射阵。通过调整相位差,使正南方向的辐射为零,计算得到初始相位差δ=252°。为了满足西南方向零辐射的要求,整体相位再偏移45°,得到初级波瓣图的表达式为E1=cos(36°cos(φ+45°)+126°)。 第二步:构建次级波瓣图 再选取一个点源位于正北方向,另一个点源位于西南方向,间距为0.4λ。调整相位差使西南方向的辐射为零,计算得到相位差δ=280°。同样整体偏移45°,得到次级波瓣图的表达式为E2=cos(72°cos(φ+45°)+140°)。 最终组合: 将初级波瓣图E1和次级波瓣图E2相乘,得到总阵的波瓣图E=E1×E2=cos(36°cos(φ+45°)+126°)×cos(72°cos(φ+45°)+140°)。通过编程实现计算并绘制波瓣图,可以看到三个阶段的波瓣图分别对应初级波瓣、次级波瓣和总波瓣,最终得到满足广播电台需求的总波瓣图。实验代码使用MATLAB编写,利用polar函数在极坐标下绘制波瓣图,并通过subplot分块显示不同阶段的波瓣图。这种设计方法体现了天线阵列设计的基本原理,即通过调整天线间的相对位置和相位关系,控制电磁波的辐射方向和强度,以满足特定的覆盖需求。这种设计在雷达、卫星通信和移动通信基站等无线通信系统中得到了广泛应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值