2014-11-05 16 views
14

Trong dự án Android của tôi, tôi có rất nhiều nơi cần chạy một số mã không đồng bộ (yêu cầu web, gọi tới db, v.v.) . Đây không phải là nhiệm vụ chạy dài (tối đa một vài giây). Cho đến bây giờ, tôi đã thực hiện loại công cụ này với việc tạo một luồng mới, truyền cho nó một runnable mới với nhiệm vụ. Nhưng gần đây tôi đã đọc một bài báo về các chủ đề và sự tương tranh trong Java và hiểu rằng việc tạo ra một Chủ đề mới cho mỗi công việc duy nhất không phải là một quyết định tốt.Chủ đề mới (nhiệm vụ) .start() VS ThreadPoolExecutor.submit (tác vụ) trong Android

Vì vậy, bây giờ tôi đã tạo một ThreadPoolExecutor trong lớp học Application chứa 5 chủ đề của mình. Đây là mã:

public class App extends Application { 

    private ThreadPoolExecutor mPool; 

    @Override 
    public void onCreate() { 
     super.onCreate(); 

     mPool = (ThreadPoolExecutor)Executors.newFixedThreadPool(5); 
    } 
} 

Và tôi cũng có một phương pháp nộp nhiệm vụ Runnable để người thi hành:

public void submitRunnableTask(Runnable task){ 
    if(!mPool.isShutdown() && mPool.getActiveCount() != mPool.getMaximumPoolSize()){ 
     mPool.submit(task); 
    } else { 
     new Thread(task).start(); 
    } 
} 

Vì vậy, khi tôi muốn chạy một nhiệm vụ không đồng bộ trong mã của tôi tôi nhận được ví dụ của App và gọi phương thức submitRunnableTask bằng cách truyền nội dung chạy đến đó. Như bạn thấy, tôi cũng kiểm tra, nếu thread thread có thread miễn phí để thực hiện nhiệm vụ của tôi, nếu không, tôi tạo một Thread mới (tôi không nghĩ rằng điều này sẽ xảy ra, nhưng trong mọi trường hợp ... I don ' t muốn công việc của tôi chờ trong hàng đợi và làm chậm ứng dụng).

Trong phương thức gọi lại onTerminate của Ứng dụng tôi tắt hồ bơi.

Vì vậy, câu hỏi của tôi là như sau: Đây có phải là mô hình tốt hơn sau đó tạo Chủ đề mới trong mã không? Những ưu và nhược điểm mà cách tiếp cận mới của tôi có? Nó có thể gây ra vấn đề mà tôi chưa biết? Bạn có thể tư vấn cho tôi điều gì đó tốt hơn điều này để quản lý các tác vụ không đồng bộ của tôi không?

P.S. Tôi có một số kinh nghiệm trong Android và Java, nhưng tôi không phải là một guru đồng thời) Vì vậy, có thể có những khía cạnh mà tôi không hiểu rõ về loại câu hỏi này. Mọi lời khuyên sẽ được đánh giá cao.

+2

Một ThreadPool tránh chi phí đáng kể trong việc tạo và hủy một chuỗi cho mỗi tác vụ mới. Ngoài ra, nó cho phép bạn có một số loại của một chính sách quản lý bao nhiêu chủ đề công nhân tồn tại tại bất kỳ thời điểm nào thay vì chỉ để cho nó xảy ra tuy nhiên nó sẽ xảy ra. Ngoài ra, nó giúp bạn tiết kiệm từ tái phát minh máy móc để đóng tất cả xuống nếu đó là một cái gì đó ứng dụng của bạn cần phải làm. –

+1

Tôi quản lý một số dự án mã nguồn mở cho cả ứng dụng Song song nhiệm vụ và dữ liệu song song. Đây là một bài viết hoạt động cho Android: http://coopsoft.com/ar/AndroidArticle.html – edharned

+0

@edharned, cảm ơn bạn rất nhiều, nhưng ấn tượng đầu tiên của tôi là khung công tác của bạn quá phức tạp đối với trường hợp của tôi.Tôi chỉ cần thực hiện một số yêu cầu JSON-RPC nhỏ và một số truy vấn cơ sở dữ liệu. Mặc dù tôi chưa nghiên cứu chi tiết khung của bạn và có thể là ấn tượng đầu tiên của tôi là sai. – Andranik

Trả lời

19

câu trả lời này giả định nhiệm vụ của bạn là ngắn

là loại mô hình tốt hơn sau đó tạo Chủ đề mới trong mã?

Tốt hơn, nhưng nó vẫn còn xa lý tưởng. Bạn đang vẫn đang tạo chuỗi cho các tác vụ ngắn. Thay vào đó, bạn chỉ cần tạo một loại nhóm luồng khác - ví dụ: Executors.newScheduledThreadPool(int corePoolSize).

Sự khác biệt trong hành vi là gì?

  • A FixedThreadPool sẽ luôn có một chuỗi chủ đề để sử dụng và nếu tất cả các chuỗi đang bận, một tác vụ mới sẽ được xếp vào hàng đợi.
  • A (mặc định) ScheduledThreadPool, được tạo bởi lớp Executors, có một hồ sơ chủ đề tối thiểu mà nó giữ, ngay cả khi không hoạt động. Nếu tất cả các chủ đề đang bận khi một tác vụ mới đến, nó tạo một chủ đề mới cho nó và hủy bỏ chủ đề 60 giây sau khi hoàn tất, trừ khi nó cần lại.

Thứ hai có thể cho phép bạn không tự tạo chủ đề mới. Hành vi này có thể đạt được mà không có phần "Theo lịch biểu", nhưng sau đó bạn sẽ phải tự xây dựng trình quản lý. Nhà xây dựng là

public ThreadPoolExecutor(int corePoolSize, 
          int maximumPoolSize, 
          long keepAliveTime, 
          TimeUnit unit, 
          BlockingQueue<Runnable> workQueue) 

Các tùy chọn khác nhau cho phép bạn tinh chỉnh hành vi.

Nếu một số nhiệm vụ dài ...

Và tôi muốn nói từ lâu. Như trong hầu hết thời gian sử dụng ứng dụng của bạn (kết nối 2 chiều thời gian thực? Cổng máy chủ? Trình nghe đa hướng?). Trong trường hợp đó, đặt Runnable của bạn trong một người thi hành là những người thực thi tiêu chuẩn bất lợi là không phải được thiết kế để đối phó với nó và hiệu suất của chúng sẽ xấu đi.

Hãy suy nghĩ về hồ bơi cố định của bạn - nếu bạn có 5 nhiệm vụ chạy dài, thì bất kỳ nhiệm vụ mới nào sẽ sinh ra một chuỗi mới, phá hủy hoàn toàn mọi lợi ích có thể có của hồ bơi. Nếu bạn sử dụng trình thực thi linh hoạt hơn - một số luồng sẽ được chia sẻ, nhưng không phải lúc nào cũng vậy.

Nguyên tắc hàng đầu là

  • Nếu đó là một nhiệm vụ ngắn - sử dụng một chấp hành viên.
  • Nếu đó là một nhiệm vụ lâu - đảm bảo thi hành di chúc của bạn có thể xử lý nó (tức là nó hoặc không có một hồ bơi kích thước tối đa, hoặc đủ đề tối đa để đối phó với 1 chủ đề hơn được đi trong một thời gian)
  • Nếu đó là một quá trình song song cần phải luôn luôn chạy cùng với chủ đề chính của bạn - hãy sử dụng một Chủ đề khác.
+0

cảm ơn bạn đã trả lời chi tiết. Tôi đã thử 'ScheduledThreadPool', nhưng có vẻ như nó không tạo ra các luồng mới khi tất cả các luồng của nó đang bận. Tôi tạo ra nó với 2 lõi chủ đề để kiểm tra '(ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool (2)' và sau đó tôi chạy rất nhiều nhiệm vụ, nhưng 'getActiveCount()' và 'getLargestPoolSize()' không bao giờ đi trên 2. Có thể tôi là làm gì sai? – Andranik

+1

@Andranik Điều đó không có vẻ giống như một cách tốt để kiểm tra xem số lượng chuỗi có tăng lên hay không. Bạn đã thử gửi một số tác vụ thắt chặt chưa? Và bạn sẽ phải kiểm tra xem trong Android nó có thực sự tạo ra hồ bơi với kích thước hồ bơi không bị ràng buộc - tôi chỉ có SE Java được thiết lập atm – Ordous

+0

Tôi chưa thử với các vòng lặp chặt chẽ, nhưng tôi nghĩ nó sẽ không tạo ra. Trong tài liệu Android tôi đã đọc bài này _Trong trường hợp này, vì nó hoạt động như một hồ bơi có kích thước cố định bằng cách sử dụng các chủ đề corePoolSize và một hàng đợi không bị chặn, điều chỉnh tối đaPoolSize không có tác dụng hữu ích._ Thành thật mà nói tôi không hiểu rõ họ muốn gì nói, nhưng có vẻ như với tôi rằng nó sẽ không tạo ra những cái mới. Nó chỉ đặt chúng vào hàng đợi cho đến khi một thread becumes miễn phí .. – Andranik

5

Để trả lời câu hỏi của bạn - Có, sử dụng Executor là tốt hơn so với tạo chủ đề mới vì:

  1. Executor cung cấp một lựa chọn các hồ bơi chủ đề khác nhau. Nó cho phép tái sử dụng các chủ đề đã tồn tại làm tăng hiệu năng khi tạo luồng là một hoạt động tốn kém.
  2. Trong trường hợp một chuỗi bị chết, Executor có thể thay thế nó bằng một chuỗi mới mà không ảnh hưởng đến ứng dụng.
  3. Các thay đổi đối với chính sách đa luồng dễ dàng hơn nhiều, vì chỉ cần thực hiện triển khai Executor.
3

Dựa trên nhận xét của Ordous Tôi đã sửa đổi mã của mình để chỉ hoạt động với một nhóm.

public class App extends Application { 

    private ThreadPoolExecutor mPool; 

    @Override 
    public void onCreate() { 
     super.onCreate(); 

     mPool = new ThreadPoolExecutor(5, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, new SynchronousQueue<Runnable>()); 
    } 
} 


public void submitRunnableTask(Runnable task){ 
    if(!mPool.isShutdown() && mPool.getActiveCount() != mPool.getMaximumPoolSize()){ 
     mPool.submit(task); 
    } else { 
     new Thread(task).start(); // Actually this should never happen, just in case... 
    } 
} 

Vì vậy, tôi hy vọng điều này có thể hữu ích cho người khác và nếu có nhiều người có ý kiến ​​về cách tiếp cận của tôi, tôi sẽ đánh giá cao nhận xét của họ.

+1

Bạn đã đi một chặng đường dài từ câu hỏi ban đầu của mình. Bạn có thể muốn đăng bài này lên CodeReview.SE để có nhận xét tốt hơn trước khi đăng nhận xét dưới dạng giải pháp hoàn chỉnh. Tôi sẽ cung cấp một ở đây mặc dù: Bạn có thể có được hành vi tương tự với 1 hồ bơi: 'mPool = new ThreadPoolExecutor (5, Integer.MAX_VALUE, 1, TimeUnit.MINUTES, mới SynchronousQueue ());'. – Ordous

+0

@Ordous, cảm ơn bạn. Tôi đã chỉnh sửa câu trả lời của mình. Ngoài ra tôi đã đánh dấu câu trả lời đầu tiên của bạn là câu trả lời đúng, vì nó trả lời tốt hơn cho câu hỏi ban đầu của tôi. – Andranik

Các vấn đề liên quan