



  

<!DOCTYPE html>
<html
  lang="en"
  
  data-color-mode="auto" data-light-theme="light" data-dark-theme="dark"
  data-a11y-animated-images="system" data-a11y-link-underlines="true"
  
  >




  <head>
    <meta charset="utf-8">
  <link rel="dns-prefetch" href="https://github.githubassets.com">
  <link rel="dns-prefetch" href="https://avatars.githubusercontent.com">
  <link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com">
  <link rel="dns-prefetch" href="https://user-images.githubusercontent.com/">
  <link rel="preconnect" href="https://github.githubassets.com" crossorigin>
  <link rel="preconnect" href="https://avatars.githubusercontent.com">

<script type="importmap">{"imports":{"react":"https://github.githubassets.com/assets/react-e27d1b3e03961e68.js","react-dom":"https://github.githubassets.com/assets/react-dom-e5fd46a22d5c4058.js","react-dom/client":"https://github.githubassets.com/assets/react-dom-client-1b4a3ee065998cea.js","react-is":"https://github.githubassets.com/assets/react-is-e0b593954b4706d8.js","react-reconciler":"https://github.githubassets.com/assets/react-reconciler-8e99e505c4429605.js","react/compiler-runtime":"https://github.githubassets.com/assets/react-compiler-runtime-4610bd6d3de9c049.js","react/jsx-dev-runtime":"https://github.githubassets.com/assets/react-jsx-dev-runtime-ea55d68667d559e5.js","react/jsx-runtime":"https://github.githubassets.com/assets/react-jsx-runtime-4915cb0f5b3aff04.js","scheduler":"https://github.githubassets.com/assets/scheduler-58b860b049ca307c.js"}}</script>
<meta name="react-profiling" content="0" data-turbo-transient="true" />
<meta name="react-import-map" content="react,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@777f63f87cd0" data-turbo-track="reload" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-e27d1b3e03961e68.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-compiler-runtime-4610bd6d3de9c049.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/scheduler-58b860b049ca307c.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-dom-e5fd46a22d5c4058.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-dom-client-1b4a3ee065998cea.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-is-e0b593954b4706d8.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-jsx-runtime-4915cb0f5b3aff04.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-reconciler-8e99e505c4429605.js" />

  


  <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light-99f877e9ddfc0e51.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light_high_contrast-48fdd0811afbab3c.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark-79ad2ace604703b3.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark_high_contrast-24484a076f02295f.css" /><link data-color-theme="light" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light-99f877e9ddfc0e51.css" /><link data-color-theme="light_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_high_contrast-48fdd0811afbab3c.css" /><link data-color-theme="light_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind-f4bf1142976e4bbf.css" /><link data-color-theme="light_colorblind_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind_high_contrast-f661b49995ba0bd8.css" /><link data-color-theme="light_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia-0b38d22346321c92.css" /><link data-color-theme="light_tritanopia_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia_high_contrast-f1c62c9e70259b9f.css" /><link data-color-theme="dark" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark-79ad2ace604703b3.css" /><link data-color-theme="dark_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_high_contrast-24484a076f02295f.css" /><link data-color-theme="dark_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind-f50cacf0a86b9929.css" /><link data-color-theme="dark_colorblind_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind_high_contrast-e61d4f4ca17852c2.css" /><link data-color-theme="dark_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia-39c10993d5603fac.css" /><link data-color-theme="dark_tritanopia_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia_high_contrast-73236c840c0c7d90.css" /><link data-color-theme="dark_dimmed" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed-0de76f07cc035b10.css" /><link data-color-theme="dark_dimmed_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed_high_contrast-fd1500c8744e40d6.css" />

  <style type="text/css">
    :root {
      --tab-size-preference: 4;
    }

    pre, code {
      tab-size: var(--tab-size-preference);
    }
  </style>

    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-primitives-ed9ca172356fd545.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-1d2c7f7b52a6068b.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-54ba76e934a49d7c.css" />
    <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/github-456bd5deb85c7ecd.css" />
  <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/repository-11ee8a031c040c1a.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-2d56bdb0166c0238.css" />

  

  <script type="application/json" id="client-env">{"locale":"en","featureFlags":["actions_enable_background_steps","actions_new_hosted_runner_image_select_sizes_and_versions","activity_diff_file_tree","activity_repos_file_tree","activity_repos_overview_header","activity_repos_overview_sidebar","agent_author_search_expansion","agent_author_search_expansion_ui_pulls","alternate_user_config_repo","async_conversion_coverage_enabled","billing_billable_licenses_cost_center_bucket_fix","billing_budget_expiration","billing_cost_center_list_assigned_resources","billing_discount_threshold_notification","code_quality_enablement_banner_targeting","code_quality_remove_preview","code_view_raf_sticky_lines","codespaces_prebuild_region_target_update","coding_agent_third_party_model_ui","copilot_agent_snippy","copilot_api_agentic_issue_marshal_yaml","copilot_automation_repo_mcp_servers","copilot_automations_pagination","copilot_chat_auto_mode_v2","copilot_chat_clear_model_selection_for_default_change","copilot_chat_header_reorder","copilot_chat_max_upsell","copilot_chat_minimize_contextual","copilot_chat_models_browser_cache","copilot_chat_reduce_quota_checks","copilot_chat_vision_dotcom_chat_ga_gate","copilot_css_textarea_autosize","copilot_custom_copilots","copilot_custom_copilots_feature_preview","copilot_duplicate_thread","copilot_extensions_removal_on_marketplace","copilot_fix_failed_workflows_all_skus","copilot_hide_hovercard","copilot_immersive_embedded_draggable","copilot_immersive_embedded_header_button","copilot_immersive_file_block_transition_open","copilot_immersive_file_preview_keep_mounted","copilot_immersive_suggestion_pills","copilot_immersive_task_hyperlinking","copilot_immersive_task_within_chat_thread","copilot_mc_cli_resume_any_users_task","copilot_mission_control_agent_merge_fix_ci","copilot_mission_control_agent_merge_resolve_conflicts","copilot_mission_control_agents_repository_enablement","copilot_mission_control_early_stop","copilot_mission_control_environment_list_icons","copilot_mission_control_managed_sandbox_environments","copilot_mission_control_needs_attention","copilot_mission_control_reasoning_effort","copilot_mission_control_repo_hovercards","copilot_mission_control_sandbox_client_side_clone","copilot_mission_control_sandbox_remote_bypass","copilot_mission_control_session_filters","copilot_mission_control_task_alive_updates","copilot_mission_control_task_sharing","copilot_org_policy_page_focus_mode","copilot_pr_chat_enhancements","copilot_prominent_upgrade_button","copilot_resource_panel","copilot_share_active_subthread","copilot_spaces_ga","copilot_spaces_individual_policies_ga","copilot_spark_handle_nil_friendly_name","copilot_swe_agent_authorization_status_ui","copilot_swe_agent_automation_resource_scoped_writes","copilot_swe_agent_hide_model_picker_if_only_auto","copilot_swe_agent_issue_comment_trigger","copilot_swe_agent_pr_comment_model_picker","copilot_swe_agent_pull_request_comment_trigger","copilot_swe_agent_pull_request_merged_trigger","copilot_swe_agent_pull_request_opened_trigger","copilot_swe_agent_pull_request_synchronize_trigger","copilot_swe_agent_use_subagents","copilot_task_api_github_rest_style","copilot_task_scoped_alive_channel","copilot_token_based_billing","copilot_unconfigured_is_inherited","copilot_user_can_upgrade_plan_field","copilot_workbench_sunset","copilot_workbench_sunset_redirect","copilot_workbench_ubb","dashboard_indexeddb_caching","dashboard_lists_max_age_filter","dashboard_universe_2025_feedback_dialog","glc_code_quality_repo_settings_workflow_config","hide_github_models_ui","hyperspace_2025_logged_out_batch_1","hyperspace_2025_logged_out_batch_2","hyperspace_2025_logged_out_batch_3","in_product_messaging_datadog_monitoring","ipm_global_transactional_message_copilot","ipm_global_transactional_message_issues","ipm_global_transactional_message_prs","ipm_global_transactional_message_repos","ipm_global_transactional_message_spaces","ipm_ubb_individual_budget_banner","issue_fields_multi_select","issue_inline_avatars","issue_pinned_views","issue_pinned_views_optimistic_updates","issue_relative_time_micro","issues_dashboard_sso_structured_errors","issues_expanded_file_types","issues_hide_closed_sub_issues","issues_lazy_load_comment_box_suggestions","issues_react_chrome_container_query_fix","labels_archiving","labels_archiving_info","landing_pages_ninetailed","lifecycle_label_name_updates","marketing_cookie_consent_banner","marketing_pages_search_explore_provider","memex_default_issue_create_repository","memex_lazy_hydrate_agent_tasks","memex_live_update_hovercard","memex_mwl_filter_field_delimiter","memex_remove_deprecated_type_issue","merge_queue_restricted_pushers_warning","merge_status_checks_refetch_dedupe","merge_status_header_feedback","oauth_authorize_clickjacking_protection","octocaptcha_origin_optimization","primer_react_css_anchor_positioning","primer_react_merged_forwarded_refs","prs_copilot_app_open_action","prs_css_anchor_positioning","pull_request_commit_checks_dialog","pull_request_copilot_attribution_header","pull_request_overview_panel_edit_description","pull_request_persister","pull_request_stacks_feedback_dialog","pull_request_virtualization_image_estimate","pull_request_virtualization_scroll_compensation","pull_request_virtualization_scroll_intent","pulls_dashboard_sidebar_layout","quick_search_lazy_suggestions","react_blob_isolate_code_lines","react_blob_ssr_content_visibility","react_data_router_tanstack_allowed","react_query_props_with_key","react_sandbox_future_tanstack","repo_app_turbo","repo_issues_sidebar_layout","repo_pulls_dashboard_persistence","repos_contributors_limited_default_range","review_involves_filter","rule_ignored_file_paths","rulesets_actor_list_editor","sample_network_conn_type","security_center_artifact_filters_popover","see_who_reacted","semantic_similarity_duplicate_issue_detection","session_logs_ungroup_reasoning_text","set_sha256_on_repo_creation_form","site_banner_desktop_copilot_app","site_ghca_pixel_mona","site_github_app_ga_page","site_github_app_ga_page_highlight","site_github_app_mobile_native_share","site_global_banner_dev_days_attendee","site_global_banner_learn_copilot_sdk","site_global_nav_spark_models_removed","spark_prompt_secret_scanning","spark_server_connection_status","suggest_custom_property_values_copilot","suppress_automated_browser_vitals","swp_forms_disable_octocaptcha","thread_resolution_reason","ui_service_referrer_metrics","ui_service_staleness_detection","update_issue_suggestions","user_code_paste_ux","viewscreen_sandbox","warn_inaccessible_attachments","webp_support","workbench_store_readonly","workstream_plugin_bootstrap"],"githubDomain":"https://github.com","copilotApiOverrideUrl":"https://api.githubcopilot.com","cmcApiUrl":"https://api.github.com/cmc_internal/api"}</script>
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/high-contrast-cookie-e3d808ee18eb9784.js"></script>
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wp-runtime-ae0eff94891055ce.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-foundation-74e9766bd696d26a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/app-runtime-eed8df9c2267c378.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fetch-utilities-5305162aa9984914.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ser-cd1b421ad0ad7ed5.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/environment-26d9b1f1bcf08ddc.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/app-runtime.94e436d05b4d028c.module.css" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/catalyst-86a8f5de995615f8.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/selector-observer-e88088f989b27670.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/relative-time-element-7cdf4e0db98b997c.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/by-6b3c07383371bf58.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ja9-36f036c13c2e3a4c.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/kw-866fd9513ae95106.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/r1-b075aab3204f32f9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/jz5-7c5d1669717041f8.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hj-5126390ff433704d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j05-dce4d588268f0f7e.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/github-elements-02d951b98309c8d6.js" defer="defer"></script>
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/element-registry-569ec65d97486cc6.js" defer="defer"></script>
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/runtime-helpers-f3f5d71440009c48.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/aria-live-76b18916d0c8ec4d.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hotkey-5109c77d7ac61078.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/react-core-fbb00aaa3ab9abdf.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/04-9cb1f09b927a3a68.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/urv-b9498edf8699ddd8.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4t-364e19c63d726e9a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/6ny-c969fbae697a356f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/yhq-3a209035a30b1a09.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/z1v-da5b33b877bfa358.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wo-09f85d22a6c8931b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/9y-81cfe57dc9040f3e.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j0-41a4cf04cbd99503.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/0p-81491ed0d9d666e2.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/behaviors-99fd526b47d131cf.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/react-core.5858534b1c27f133.module.css" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/code-menu-09270eeff232a05b.js" defer="defer"></script>
  
  <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/primer-react-12ebdc24dcff1ecc.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ncx-9a860680a5f230b9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j6-363f0ebf4f62f310.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/t7l-bf6f21d7e7a43c35.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fe-7576d9b281e2106a.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wsr-5fd3071e5a9061ab.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/0n-ecadb2ffe6b01ba2.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/xv-51cb34754bda73a9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/n4u-6317ce1c31aed1db.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/j8s-d90ce3a169b741ed.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/la-de176c4ee471f2b3.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/eag-d9eea130fa716df9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/y2-87df441f1bc5a264.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/kcz-607e36c8a3751cf0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/x4-65dba777efd828f3.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/gzu-1a09248f686325f6.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/on-95be29ba1ef725d9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/bi0-e2f78de823e39ca9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/b1-1dbc371cef78c3c1.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/0l5-55aa9485c732f0ca.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/c2z-c92998400310b94b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/f9-038758dcbfe08dab.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/0k-b7df0a74912a42bf.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/sp-2bbb73a69162e23b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/og-93ae8b358505d372.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/b9-69d9b60a1b1fcd59.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ec-ec74cb1fa6c31a3f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/du-bbe0f39cd2abe9a0.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ql0-6accb9e40c25a6a5.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/20-0a2e46387735f1f4.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/dsj-cb1e4ddbce4f007b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/wp-9f5235d335ab624b.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/ko6-9e80f7ac359e3c43.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/uw-8c275f7ac25b7cf6.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/bsb-4f4ac8c20da73fac.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/w5-13e3a7548bb20af9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fm-9bc913d1959fabab.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/z-69921967c33df3d9.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/h0-010921512138e12f.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/5p-ae5db0820116fb43.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/8vq-b2af216e992e11ef.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/g5-b501f75e99f2d2c4.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/xc-f5d51b571cd317cb.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/arw-51e8918a1b75a80f.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/code-view-966ac9fdde34c59b.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.9d59d1018a52a53c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/ql0.bd9e6b542f167fd8.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/z.3094038d30e96da5.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/xc.13e027137438fd9f.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/code-view.ee0d7b9d6bba8dd4.module.css" />

  <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/hu-1fc0b2a167afc025.js" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fbr-9cd34ba01ef26edb.js" />
<script crossorigin="anonymous" type="module" src="https://github.githubassets.com/assets/notifications-subscriptions-menu-1dcbb9a5e503d95b.js" defer="defer"></script>
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.9d59d1018a52a53c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/notifications-subscriptions-menu.4bd8ebaa031d780a.module.css" />


  <title>JavaGuide/docs/java/collection/arrayblockingqueue-source-code.md at main · cht37/JavaGuide · GitHub</title>



  <meta name="route-pattern" content="/:user_id/:repository/blob/*name(/*path)" data-turbo-transient>
  <meta name="route-controller" content="blob" data-turbo-transient>
  <meta name="route-action" content="show" data-turbo-transient>
  <meta name="fetch-nonce" content="v2:f72f61f9-5c45-d3d6-525f-47115ccc3b14">

    
  <meta name="current-catalog-service-hash" content="f3abb0cc802f3d7b95fc8762b94bdcb13bf39634c40c357301c4aa1d67a256fb">


  <meta name="request-id" content="E0D8:B110C:4B74090:49346DF:6AAB9C8F" data-pjax-transient="true"/><meta name="html-safe-nonce" content="9ec313f8cdeaa0a175997bf54516a5d5e0b575eb98f9d34698f1ca231424d0bc" data-pjax-transient="true"/><meta name="visitor-payload" content="eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFMEQ4OkIxMTBDOjRCNzQwOTA6NDkzNDZERjo2QUFCOUM4RiIsInZpc2l0b3JfaWQiOiI4OTYxNzc3Mjg4NzI1ODk2MzM1IiwicmVnaW9uX2VkZ2UiOiJmcmEiLCJyZWdpb25fcmVuZGVyIjoiZnJhIn0=" data-pjax-transient="true"/><meta name="visitor-hmac" content="d75a2a42bec36b283bfd2d7874f609ba75042fb75a9a5a4f29504435a2b7ef91" data-pjax-transient="true"/>


    <meta name="hovercard-subject-tag" content="repository:758919476" data-turbo-transient>


  <meta name="github-keyboard-shortcuts" content="repository,source-code,file-tree,copilot" data-turbo-transient="true" />
  

  <meta name="selected-link" value="repo_source" data-turbo-transient>
  <link rel="assets" href="https://github.githubassets.com/">

    <meta name="google-site-verification" content="Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I">

<meta name="octolytics-url" content="https://collector.github.com/github/collect" />





  <meta name="analytics-location" content="/&lt;user-name&gt;/&lt;repo-name&gt;/blob/show" data-turbo-transient="true" />

  




    <meta name="user-login" content="">

  

    <meta name="viewport" content="width=device-width">

    

      <meta name="description" content="「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识。准备 Java 面试，首选 JavaGuide！ - JavaGuide/docs/java/collection/arrayblockingqueue-source-code.md at main · cht37/JavaGuide">

      <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">

    <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
    <meta property="fb:app_id" content="1401488693436528">
    <meta name="apple-itunes-app" content="app-id=1477376905, app-argument=https://github.com/cht37/JavaGuide/blob/main/docs/java/collection/arrayblockingqueue-source-code.md" />

      <meta name="twitter:image" content="https://opengraph.githubassets.com/c1121143e914efd8653cf5751b9a9eeb64c818db26fb5210c38c2f5f50f2ae74/cht37/JavaGuide" /><meta name="twitter:site" content="@github" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:title" content="JavaGuide/docs/java/collection/arrayblockingqueue-source-code.md at main · cht37/JavaGuide" /><meta name="twitter:description" content="「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识。准备 Java 面试，首选 JavaGuide！ - cht37/JavaGuide" />
  <meta property="og:image" content="https://opengraph.githubassets.com/c1121143e914efd8653cf5751b9a9eeb64c818db26fb5210c38c2f5f50f2ae74/cht37/JavaGuide" /><meta property="og:image:alt" content="「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识。准备 Java 面试，首选 JavaGuide！ - cht37/JavaGuide" /><meta property="og:image:width" content="1200" /><meta property="og:image:height" content="600" /><meta property="og:site_name" content="GitHub" /><meta property="og:type" content="object" /><meta property="og:title" content="JavaGuide/docs/java/collection/arrayblockingqueue-source-code.md at main · cht37/JavaGuide" /><meta property="og:url" content="https://github.com/cht37/JavaGuide/blob/main/docs/java/collection/arrayblockingqueue-source-code.md" /><meta property="og:description" content="「Java学习+面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识。准备 Java 面试，首选 JavaGuide！ - cht37/JavaGuide" />
  




      <meta name="hostname" content="github.com">



        <meta name="expected-hostname" content="github.com">


  <meta http-equiv="x-pjax-version" content="bbc2824628423c96bc57da960f8d748ac00bac7c7842ffd138ad16eefe9f4283" data-turbo-track="reload">
  <meta http-equiv="x-pjax-csp-version" content="0c5c6e5334a905d8f9521e09eadcffba484d422e0d262e07ff922e6bc18b2ac6" data-turbo-track="reload">
  <meta http-equiv="x-pjax-css-version" content="ec4c7b86d7b57240253150b827ea48b04e08d8760dc6553d2a04f62000f3fe0c" data-turbo-track="reload">
  <meta http-equiv="x-pjax-js-version" content="7511e25be499582d7cca7dda2b448cd388104c1812417ddcaa662b8fc8cdc31a" data-turbo-track="reload">

  <meta name="turbo-cache-control" content="no-preview" data-turbo-transient="">

      <meta name="turbo-cache-control" content="no-cache" data-turbo-transient>

    <meta data-hydrostats="publish">

  <meta name="go-import" content="github.com/cht37/JavaGuide git https://github.com/cht37/JavaGuide.git">

  <meta name="octolytics-dimension-user_id" content="92900292" /><meta name="octolytics-dimension-user_login" content="cht37" /><meta name="octolytics-dimension-repository_id" content="758919476" /><meta name="octolytics-dimension-repository_nwo" content="cht37/JavaGuide" /><meta name="octolytics-dimension-repository_public" content="true" /><meta name="octolytics-dimension-repository_is_fork" content="true" /><meta name="octolytics-dimension-repository_parent_id" content="132464395" /><meta name="octolytics-dimension-repository_parent_nwo" content="Snailclimb/JavaGuide" /><meta name="octolytics-dimension-repository_network_root_id" content="132464395" /><meta name="octolytics-dimension-repository_network_root_nwo" content="Snailclimb/JavaGuide" />
  



    

    <meta name="turbo-body-classes" content="logged-out env-production page-responsive">
  <meta name="disable-turbo" content="false">


  <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats">


  <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors">

  <meta name="release" content="ad11ba3e78b8c3f0ac9d95b25983996b4a3bc105" data-turbo-track="reload">
  <meta name="ui-target" content="full">

  <link rel="mask-icon" href="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" color="#000000">
  <link rel="alternate icon" class="js-site-favicon" type="image/png" href="https://github.githubassets.com/favicons/favicon.png">
  <link rel="icon" class="js-site-favicon" type="image/svg+xml" href="https://github.githubassets.com/favicons/favicon.svg" data-base-href="https://github.githubassets.com/favicons/favicon">

<meta name="theme-color" content="#1e2327">
<meta name="color-scheme" content="light dark" />


  <link rel="manifest" href="/manifest.json" crossOrigin="use-credentials">

  </head>

  <body class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
    <div data-turbo-body class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
      <div id="__primerPortalRoot__" style="z-index: 1000; position: absolute; width: 100%;" data-turbo-permanent></div>
      

    <div class="position-relative header-wrapper js-header-wrapper ">
      <a href="#start-of-content" data-skip-target-assigned="false" class="px-2 tmp-py-4 color-bg-accent-emphasis color-fg-on-emphasis show-on-focus js-skip-to-content">Skip to content</a>

      <span data-view-component="true" class="progress-pjax-loader Progress position-fixed width-full">
    <span style="width: 0%;" data-view-component="true" class="Progress-item progress-pjax-loader-bar left-0 top-0 color-bg-accent-emphasis"></span>
</span>      
      <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/l7j-2ddd8b435dadae28.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/keyboard-shortcuts-dialog-368b66ed757ca293.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.9d59d1018a52a53c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/keyboard-shortcuts-dialog.10c2a1f5a5e8ed67.module.css" />

<react-partial
  partial-name="keyboard-shortcuts-dialog"
  data-ssr="false"
  data-attempted-ssr="false"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{"docsUrl":"https://docs.github.com/get-started/accessibility/keyboard-shortcuts"}}</script>
  <div data-target="react-partial.reactRoot"></div>
</react-partial>





      

          
          

                <link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/2l-a4cd948f93d92068.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/i26-de97ea9fb4f29e3b.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/fz5-23f28c0f388769c9.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/lht-26506ea833dda5be.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/p1-76a75a6081059b19.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/3d8-bbc4e3ce35fac150.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/tua-c4ca62c5e0e0318e.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/4s-c22d880230690e1f.js" fetchpriority="low" />
<link crossorigin="anonymous" rel="modulepreload" href="https://github.githubassets.com/assets/marketing-header-4c9c0e8a4de31246.js" fetchpriority="low" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-css.9d59d1018a52a53c.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react-brand-css.6a01c236ff527e7e.module.css" />
<link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/4s.e3d02f110161be52.module.css" />

<react-partial
  partial-name="marketing-header"
  data-ssr="true"
  data-attempted-ssr="true"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-partial.embeddedData">{"props":{"color_mode":"dark","logged_in":false,"marketing_page":false,"home_path":"/","login_path":"/login?return_to=https%3A%2F%2Fgithub.com%2Fcht37%2FJavaGuide%2Fblob%2Fmain%2Fdocs%2Fjava%2Fcollection%2Farrayblockingqueue-source-code.md","signup_path":"/signup?ref_cta=Sign+up\u0026ref_loc=header+logged+out\u0026ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fblob%2Fshow\u0026source=header-repo\u0026source_repo=cht37%2FJavaGuide","signup_enabled":true,"is_signup_controller":false,"show_search_and_nav":true,"hide_search":false,"private_mode_enabled":false,"should_use_dotcom_links":true,"auth_hydro_click":"{\"event_type\":\"authentication.click\",\"payload\":{\"location_in_page\":\"site header menu\",\"repository_id\":null,\"auth_type\":\"SIGN_UP\",\"originating_url\":\"https://github.com/cht37/JavaGuide/blob/main/docs/java/collection/arrayblockingqueue-source-code.md\",\"user_id\":null}}","auth_hydro_click_hmac":"cdabdc98c705ecb274e2c9b18b2adec933089ca950627aa4689b63cde73f6152","overlay":false,"fixed":false}}</script>
  <div data-target="react-partial.reactRoot"><div data-color-mode="dark" data-light-theme="light" data-dark-theme="dark"><header class="MarketingHeader-module__root__Tk7n3 HeaderMktg header-logged-out" role="banner" data-marketing-header="true" data-color-mode="dark" data-light-theme="light" data-dark-theme="dark" data-is-top="true"><h2 class="MarketingHeader-module__visuallyHidden__sqKsl">Navigation Menu</h2><button type="button" class="MarketingHeader-module__backdrop__sw4RU" aria-label="Close navigation menu"></button><div class="MarketingHeader-module__bar__mBSyE"><div class="MarketingHeader-module__topRow__yeury"><div class="MarketingHeader-module__toggleSlot__hDxbh"><button type="button" class="HeaderMenuToggle-module__toggle__i8EiC" aria-label="Toggle navigation" aria-expanded="false"><span class="HeaderMenuToggle-module__toggleBar__jVN0H"></span><span class="HeaderMenuToggle-module__toggleBar__jVN0H"></span><span class="HeaderMenuToggle-module__toggleBar__jVN0H"></span></button></div><a href="/" aria-label="Homepage" class="HeaderLogo-module__logo__UFyHI" data-analytics-event="{&quot;action&quot;:&quot;homepage&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;logo&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;homepage_link_logo_header&quot;}"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mark-github" viewBox="0 0 24 24" width="32" height="32" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.226 17.284c-2.965-.36-5.054-2.493-5.054-5.256 0-1.123.404-2.336 1.078-3.144-.292-.741-.247-2.314.09-2.965.898-.112 2.111.36 2.83 1.01.853-.269 1.752-.404 2.853-.404 1.1 0 1.999.135 2.807.382.696-.629 1.932-1.1 2.83-.988.315.606.36 2.179.067 2.942.72.854 1.101 2 1.101 3.167 0 2.763-2.089 4.852-5.098 5.234.763.494 1.28 1.572 1.28 2.807v2.336c0 .674.561 1.056 1.235.786 4.066-1.55 7.255-5.615 7.255-10.646C23.5 6.188 18.334 1 11.978 1 5.62 1 .5 6.188.5 12.545c0 4.986 3.167 9.12 7.435 10.669.606.225 1.19-.18 1.19-.786V20.63a2.9 2.9 0 0 1-1.078.224c-1.483 0-2.359-.808-2.987-2.313-.247-.607-.517-.966-1.034-1.033-.27-.023-.359-.135-.359-.27 0-.27.45-.471.898-.471.652 0 1.213.404 1.797 1.235.45.651.921.943 1.483.943.561 0 .92-.202 1.437-.719.382-.381.674-.718.944-.943"></path></svg></a><div class="AuthCTAs-module__mobileActions__NNzeV"><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw AuthCTAs-module__cta__WpwQq" href="/login?return_to=https%3A%2F%2Fgithub.com%2Fcht37%2FJavaGuide%2Fblob%2Fmain%2Fdocs%2Fjava%2Fcollection%2Farrayblockingqueue-source-code.md" data-analytics-event="{&quot;action&quot;:&quot;sign_in&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;auth_cta&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;sign_in_link_auth_cta_header&quot;}" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/cht37/JavaGuide/blob/main/docs/java/collection/arrayblockingqueue-source-code.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="cdabdc98c705ecb274e2c9b18b2adec933089ca950627aa4689b63cde73f6152"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH">Sign in</span></span></a><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw HeaderAppearanceSettings-module__trigger__hUheK" type="button" aria-haspopup="dialog" aria-labelledby="_R_3dd_"><span class="Primer_Brand__Button-module__Button__leading-visual___jjtTe" data-testid="Button-leading-visual"><svg data-component="Octicon" focusable="false" aria-hidden="true" class="octicon octicon-sliders Primer_Brand__Button-module__Button__icon-visual____qybb" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M15 2.75a.75.75 0 0 1-.75.75h-4a.75.75 0 0 1 0-1.5h4a.75.75 0 0 1 .75.75Zm-8.5.75v1.25a.75.75 0 0 0 1.5 0v-4a.75.75 0 0 0-1.5 0V2H1.75a.75.75 0 0 0 0 1.5H6.5Zm1.25 5.25a.75.75 0 0 0 0-1.5h-6a.75.75 0 0 0 0 1.5h6ZM15 8a.75.75 0 0 1-.75.75H11.5V10a.75.75 0 1 1-1.5 0V6a.75.75 0 0 1 1.5 0v1.25h2.75A.75.75 0 0 1 15 8Zm-9 5.25v-2a.75.75 0 0 0-1.5 0v1.25H1.75a.75.75 0 0 0 0 1.5H4.5v1.25a.75.75 0 0 0 1.5 0v-2Zm9 0a.75.75 0 0 1-.75.75h-6a.75.75 0 0 1 0-1.5h6a.75.75 0 0 1 .75.75Z"></path></svg></span><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH"></span></span></button><div class="Primer_Brand__Tooltip-module__Tooltip___0Eipx" data-direction="s" aria-hidden="true" id="_R_3dd_">Appearance settings</div></div></div><div class="MarketingHeader-module__menu__GIy3y"><div class="MarketingHeader-module__menuWrapper__owstH"><nav class="MarketingNavigation-module__nav__W0KYY" aria-label="Global"><ul class="MarketingNavigation-module__list__tFbMb"><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_nd_">Platform<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_nd_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5knd_">AI CODE CREATION</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5knd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/copilot" data-analytics-event="{&quot;action&quot;:&quot;github_copilot&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_copilot_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copilot NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"></path><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"></path></svg>GitHub Copilot</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Write better code with AI</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/ai/github-app" data-analytics-event="{&quot;action&quot;:&quot;github_copilot_app&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_copilot_app_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mark-github NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M6.766 11.328c-2.063-.25-3.516-1.734-3.516-3.656 0-.781.281-1.625.75-2.188-.203-.515-.172-1.609.063-2.062.625-.078 1.468.25 1.968.703.594-.187 1.219-.281 1.985-.281.765 0 1.39.094 1.953.265.484-.437 1.344-.765 1.969-.687.218.422.25 1.515.046 2.047.5.593.766 1.39.766 2.203 0 1.922-1.453 3.375-3.547 3.64.531.344.89 1.094.89 1.954v1.625c0 .468.391.734.86.547C13.781 14.359 16 11.53 16 8.03 16 3.61 12.406 0 7.984 0 3.563 0 0 3.61 0 8.031a7.88 7.88 0 0 0 5.172 7.422c.422.156.828-.125.828-.547v-1.25c-.219.094-.5.156-.75.156-1.031 0-1.64-.562-2.078-1.609-.172-.422-.36-.672-.719-.719-.187-.015-.25-.093-.25-.187 0-.188.313-.328.625-.328.453 0 .844.281 1.25.86.313.452.64.655 1.031.655s.641-.14 1-.5c.266-.265.47-.5.657-.656"></path></svg>GitHub Copilot app</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Direct agents from issue to merge</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/mcp" data-analytics-event="{&quot;action&quot;:&quot;mcp_registry&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;mcp_registry_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-mcp NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5.52 1.12a3.578 3.578 0 0 1 6.078 2.98 3.578 3.578 0 0 1 2.982 6.08l-3.292 3.293a.252.252 0 0 0 0 .354l.843.843a.749.749 0 1 1-1.06 1.06l-.844-.843a1.75 1.75 0 0 1 0-2.474L13.52 9.12a2.08 2.08 0 0 0 0-2.94 2.08 2.08 0 0 0-2.94 0L7.731 9.03A.75.75 0 0 1 6.67 7.97l2.85-2.85a2.08 2.08 0 0 0 0-2.94 2.08 2.08 0 0 0-2.94 0l-4.799 4.8A.75.75 0 0 1 .72 5.92Z"></path><path d="M7.52 3.12a.749.749 0 1 1 1.06 1.06L5.731 7.03A2.079 2.079 0 0 0 8.67 9.97l2.85-2.85a.749.749 0 1 1 1.06 1.06l-2.849 2.85A3.578 3.578 0 0 1 4.67 5.97Z"></path></svg>MCP Registry</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Integrate external tools</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9knd_">DEVELOPER WORKFLOWS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9knd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/actions" data-analytics-event="{&quot;action&quot;:&quot;actions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;actions_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-workflow NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75C0 .784.784 0 1.75 0h3.5C6.216 0 7 .784 7 1.75v3.5A1.75 1.75 0 0 1 5.25 7H4v4a1 1 0 0 0 1 1h4v-1.25C9 9.784 9.784 9 10.75 9h3.5c.966 0 1.75.784 1.75 1.75v3.5A1.75 1.75 0 0 1 14.25 16h-3.5A1.75 1.75 0 0 1 9 14.25v-.75H5A2.5 2.5 0 0 1 2.5 11V7h-.75A1.75 1.75 0 0 1 0 5.25Zm1.75-.25a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Zm9 9a.25.25 0 0 0-.25.25v3.5c0 .138.112.25.25.25h3.5a.25.25 0 0 0 .25-.25v-3.5a.25.25 0 0 0-.25-.25Z"></path></svg>Actions</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Automate any workflow</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/codespaces" data-analytics-event="{&quot;action&quot;:&quot;codespaces&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;codespaces_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-codespaces NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 11.25c0-.966.784-1.75 1.75-1.75h12.5c.966 0 1.75.784 1.75 1.75v3A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm2-9.5C2 .784 2.784 0 3.75 0h8.5C13.216 0 14 .784 14 1.75v5a1.75 1.75 0 0 1-1.75 1.75h-8.5A1.75 1.75 0 0 1 2 6.75Zm1.75-.25a.25.25 0 0 0-.25.25v5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-5a.25.25 0 0 0-.25-.25Zm-2 9.5a.25.25 0 0 0-.25.25v3c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25v-3a.25.25 0 0 0-.25-.25Z"></path><path d="M7 12.75a.75.75 0 0 1 .75-.75h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1-.75-.75Zm-4 0a.75.75 0 0 1 .75-.75h.5a.75.75 0 0 1 0 1.5h-.5a.75.75 0 0 1-.75-.75Z"></path></svg>Codespaces</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Instant dev environments</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/issues" data-analytics-event="{&quot;action&quot;:&quot;issues&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;issues_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-issue-opened NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Z"></path></svg>Issues</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Plan and track work</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/code-review" data-analytics-event="{&quot;action&quot;:&quot;code_review&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;code_review_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path></svg>Code Review</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Manage code changes</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/code-quality" data-analytics-event="{&quot;action&quot;:&quot;code_quality&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;code_quality_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-codescan-checkmark NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.28 6.28a.75.75 0 1 0-1.06-1.06L6.25 8.19l-.97-.97a.75.75 0 0 0-1.06 1.06l1.5 1.5a.75.75 0 0 0 1.06 0l3.5-3.5Z"></path><path d="M7.5 15a7.5 7.5 0 1 1 5.807-2.754l2.473 2.474a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2.474-2.473A7.472 7.472 0 0 1 7.5 15Zm0-13.5a6 6 0 1 0 4.094 10.386.748.748 0 0 1 .293-.292 6.002 6.002 0 0 0 1.117-6.486A6.002 6.002 0 0 0 7.5 1.5Z"></path></svg>Code Quality</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enforce quality at merge</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dknd_">APPLICATION SECURITY</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dknd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security" data-analytics-event="{&quot;action&quot;:&quot;github_advanced_security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_advanced_security_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield-check NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m8.533.133 5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68a1.748 1.748 0 0 1 1.066 0Zm-.61 1.429.001.001-5.25 1.68a.251.251 0 0 0-.174.237V7c0 1.36.275 2.666 1.057 3.859.784 1.194 2.121 2.342 4.366 3.298a.196.196 0 0 0 .154 0c2.245-.957 3.582-2.103 4.366-3.297C13.225 9.666 13.5 8.358 13.5 7V3.48a.25.25 0 0 0-.174-.238l-5.25-1.68a.25.25 0 0 0-.153 0ZM11.28 6.28l-3.5 3.5a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.97-2.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg>GitHub Advanced Security</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Find and fix vulnerabilities</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security/code-security" data-analytics-event="{&quot;action&quot;:&quot;code_security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;code_security_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-code-square NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25Zm7.47 3.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L10.69 8 9.22 6.53a.75.75 0 0 1 0-1.06ZM6.78 6.53 5.31 8l1.47 1.47a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg>Code security</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Secure your code as you build</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security/secret-protection" data-analytics-event="{&quot;action&quot;:&quot;secret_protection&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;secret_protection_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-lock NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M4 4a4 4 0 0 1 8 0v2h.25c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 12.25 15h-8.5A1.75 1.75 0 0 1 2 13.25v-5.5C2 6.784 2.784 6 3.75 6H4Zm8.25 3.5h-8.5a.25.25 0 0 0-.25.25v5.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25ZM10.5 6V4a2.5 2.5 0 1 0-5 0v2Z"></path></svg>Secret protection</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Stop leaks before they start</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ NavGroup-module__hasSeparator__FnMrN"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_hknd_">EXPLORE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_hknd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/why-github" data-analytics-event="{&quot;action&quot;:&quot;why_github&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;why_github_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Why GitHub</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://docs.github.com" data-analytics-event="{&quot;action&quot;:&quot;documentation&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;documentation_link_platform_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Documentation</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://github.blog" data-analytics-event="{&quot;action&quot;:&quot;blog&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;blog_link_platform_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Blog</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://github.blog/changelog" data-analytics-event="{&quot;action&quot;:&quot;changelog&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;changelog_link_platform_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Changelog</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/marketplace" data-analytics-event="{&quot;action&quot;:&quot;marketplace&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;marketplace_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Marketplace</span></a></li></ul></div></li></ul><div class="NavDropdown-module__trailingLinkContainer__VgJGL"><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/features" data-analytics-event="{&quot;action&quot;:&quot;view_all_features&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;platform&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_features_link_platform_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all features</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></div></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_17d_">Solutions<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_17d_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5l7d_">BY COMPANY SIZE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5l7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/enterprise" data-analytics-event="{&quot;action&quot;:&quot;enterprises&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;enterprises_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Enterprises</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/team" data-analytics-event="{&quot;action&quot;:&quot;small_and_medium_teams&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;small_and_medium_teams_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Small and medium teams</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/enterprise/startups" data-analytics-event="{&quot;action&quot;:&quot;startups&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;startups_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Startups</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/nonprofits" data-analytics-event="{&quot;action&quot;:&quot;nonprofits&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;nonprofits_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Nonprofits</span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9l7d_">BY USE CASE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9l7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/app-modernization" data-analytics-event="{&quot;action&quot;:&quot;app_modernization&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;app_modernization_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">App Modernization</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/devsecops" data-analytics-event="{&quot;action&quot;:&quot;devsecops&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;devsecops_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">DevSecOps</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/devops" data-analytics-event="{&quot;action&quot;:&quot;devops&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;devops_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">DevOps</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/use-case/ci-cd" data-analytics-event="{&quot;action&quot;:&quot;ci/cd&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;ci/cd_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">CI/CD</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/solutions/use-case" data-analytics-event="{&quot;action&quot;:&quot;view_all_use_cases&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_use_cases_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all use cases</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dl7d_">BY INDUSTRY</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dl7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/healthcare" data-analytics-event="{&quot;action&quot;:&quot;healthcare&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;healthcare_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Healthcare</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/financial-services" data-analytics-event="{&quot;action&quot;:&quot;financial_services&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;financial_services_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Financial services</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/manufacturing" data-analytics-event="{&quot;action&quot;:&quot;manufacturing&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;manufacturing_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Manufacturing</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/industry/government" data-analytics-event="{&quot;action&quot;:&quot;government&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;government_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Government</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/solutions/industry" data-analytics-event="{&quot;action&quot;:&quot;view_all_industries&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_industries_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all industries</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></li></ul></div></li></ul><div class="NavDropdown-module__trailingLinkContainer__VgJGL"><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/solutions" data-analytics-event="{&quot;action&quot;:&quot;view_all_solutions&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;solutions&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_solutions_link_solutions_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all solutions</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></div></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_1nd_">Resources<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_1nd_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5lnd_">EXPLORE BY TOPIC</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5lnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=ai" data-analytics-event="{&quot;action&quot;:&quot;ai&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;ai_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">AI</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=software-development" data-analytics-event="{&quot;action&quot;:&quot;software_development&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;software_development_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Software Development</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=devops" data-analytics-event="{&quot;action&quot;:&quot;devops&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;devops_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">DevOps</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/articles?topic=security" data-analytics-event="{&quot;action&quot;:&quot;security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;security_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Security</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/resources/articles" data-analytics-event="{&quot;action&quot;:&quot;view_all_topics&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_topics_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all topics</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9lnd_">EXPLORE BY TYPE</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9lnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/customer-stories" data-analytics-event="{&quot;action&quot;:&quot;customer_stories&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;customer_stories_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Customer stories</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/events" data-analytics-event="{&quot;action&quot;:&quot;events__webinars&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;events__webinars_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Events &amp; webinars</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/resources/whitepapers" data-analytics-event="{&quot;action&quot;:&quot;ebooks__reports&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;ebooks__reports_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Ebooks &amp; reports</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/solutions/executive-insights" data-analytics-event="{&quot;action&quot;:&quot;business_insights&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;business_insights_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Business insights</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://skills.github.com" data-analytics-event="{&quot;action&quot;:&quot;github_skills&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_skills_link_resources_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">GitHub Skills</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dlnd_">SUPPORT &amp; SERVICES</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dlnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://docs.github.com" data-analytics-event="{&quot;action&quot;:&quot;documentation&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;documentation_link_resources_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Documentation</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://support.github.com" data-analytics-event="{&quot;action&quot;:&quot;customer_support&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;customer_support_link_resources_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Customer support</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/orgs/community/discussions" data-analytics-event="{&quot;action&quot;:&quot;community_forum&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;community_forum_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Community forum</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/trust-center" data-analytics-event="{&quot;action&quot;:&quot;trust_center&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;trust_center_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Trust center</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/partners" data-analytics-event="{&quot;action&quot;:&quot;partners&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;partners_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Partners</span></a></li></ul></div></li></ul><div class="NavDropdown-module__trailingLinkContainer__VgJGL"><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--arrow-end___esdN8" href="https://github.com/resources" data-analytics-event="{&quot;action&quot;:&quot;view_all_resources&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;resources&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;view_all_resources_link_resources_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">View all resources</span><svg class="Primer_Brand__ExpandableArrow-module__ExpandableArrow___aaZs9 Primer_Brand__Link-module__Link-arrow___yd78i" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true" focusable="false"><path fill="currentColor" d="M7.28033 3.21967C6.98744 2.92678 6.51256 2.92678 6.21967 3.21967C5.92678 3.51256 5.92678 3.98744 6.21967 4.28033L7.28033 3.21967ZM11 8L11.5303 8.53033C11.8232 8.23744 11.8232 7.76256 11.5303 7.46967L11 8ZM6.21967 11.7197C5.92678 12.0126 5.92678 12.4874 6.21967 12.7803C6.51256 13.0732 6.98744 13.0732 7.28033 12.7803L6.21967 11.7197ZM6.21967 4.28033L10.4697 8.53033L11.5303 7.46967L7.28033 3.21967L6.21967 4.28033ZM10.4697 7.46967L6.21967 11.7197L7.28033 12.7803L11.5303 8.53033L10.4697 7.46967Z"></path><path class="Primer_Brand__ExpandableArrow-module__ExpandableArrow-stem___0K8Hz" stroke="currentColor" d="M1.75 8H11" stroke-width="1.5" stroke-linecap="round"></path></svg></a></div></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_27d_">Open Source<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_27d_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5m7d_">COMMUNITY</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5m7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/open-source/sponsors" data-analytics-event="{&quot;action&quot;:&quot;github_sponsors&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_sponsors_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-sponsor-tiers NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.586 1C12.268 1 13.5 2.37 13.5 4.25c0 1.745-.996 3.359-2.622 4.831-.166.15-.336.297-.509.438l1.116 5.584a.75.75 0 0 1-.991.852l-2.409-.876a.25.25 0 0 0-.17 0l-2.409.876a.75.75 0 0 1-.991-.852L5.63 9.519a13.78 13.78 0 0 1-.51-.438C3.497 7.609 2.5 5.995 2.5 4.25 2.5 2.37 3.732 1 5.414 1c.963 0 1.843.403 2.474 1.073L8 2.198l.112-.125a3.385 3.385 0 0 1 2.283-1.068L10.586 1Zm-3.621 9.495-.718 3.594 1.155-.42a1.75 1.75 0 0 1 1.028-.051l.168.051 1.154.42-.718-3.592c-.199.13-.37.235-.505.314l-.169.097a.75.75 0 0 1-.72 0 9.54 9.54 0 0 1-.515-.308l-.16-.105ZM10.586 2.5c-.863 0-1.611.58-1.866 1.459-.209.721-1.231.721-1.44 0C7.025 3.08 6.277 2.5 5.414 2.5 4.598 2.5 4 3.165 4 4.25c0 1.23.786 2.504 2.128 3.719.49.443 1.018.846 1.546 1.198l.325.21.076-.047.251-.163a13.341 13.341 0 0 0 1.546-1.198C11.214 6.754 12 5.479 12 4.25c0-1.085-.598-1.75-1.414-1.75Z"></path></svg>GitHub Sponsors</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Fund open source developers</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9m7d_">PROGRAMS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9m7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://securitylab.github.com" data-analytics-event="{&quot;action&quot;:&quot;security_lab&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;security_lab_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Security Lab</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://maintainers.github.com" data-analytics-event="{&quot;action&quot;:&quot;maintainer_community&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;maintainer_community_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Maintainer Community</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://stars.github.com" data-analytics-event="{&quot;action&quot;:&quot;github_stars&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_stars_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">GitHub Stars</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 Primer_Brand__Link-module__Link--is-external___xsncV" href="https://archiveprogram.github.com" data-analytics-event="{&quot;action&quot;:&quot;archive_program&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;archive_program_link_open_source_navbar&quot;}" target="_blank" rel="noreferrer"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Archive Program</span><svg data-component="Octicon" focusable="false" aria-label="External link" class="octicon octicon-link-external" role="img" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.75 2h3.5a.75.75 0 0 1 0 1.5h-3.5a.25.25 0 0 0-.25.25v8.5c0 .138.112.25.25.25h8.5a.25.25 0 0 0 .25-.25v-3.5a.75.75 0 0 1 1.5 0v3.5A1.75 1.75 0 0 1 12.25 14h-8.5A1.75 1.75 0 0 1 2 12.25v-8.5C2 2.784 2.784 2 3.75 2Zm6.854-1h4.146a.25.25 0 0 1 .25.25v4.146a.25.25 0 0 1-.427.177L13.03 4.03 9.28 7.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.75-3.75-1.543-1.543A.25.25 0 0 1 10.604 1Z"></path></svg></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_dm7d_">REPOSITORIES</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_dm7d_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/topics" data-analytics-event="{&quot;action&quot;:&quot;topics&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;topics_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Topics</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/trending" data-analytics-event="{&quot;action&quot;:&quot;trending&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;trending_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Trending</span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0" href="https://github.com/collections" data-analytics-event="{&quot;action&quot;:&quot;collections&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;open_source&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;collections_link_open_source_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty">Collections</span></a></li></ul></div></li></ul></div></div></li><li><div class="NavDropdown-module__container__l2YeI"><button type="button" class="NavDropdown-module__button__PEHWX" aria-expanded="false" aria-controls="_R_2nd_">Enterprise<svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-right NavDropdown-module__buttonIcon__Tkl8_" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m6.427 4.427 3.396 3.396a.25.25 0 0 1 0 .354l-3.396 3.396A.25.25 0 0 1 6 11.396V4.604a.25.25 0 0 1 .427-.177Z"></path></svg></button><div id="_R_2nd_" class="NavDropdown-module__dropdown__xm1jd"><ul class="NavDropdown-module__list__zuCgG"><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_5mnd_">ENTERPRISE SOLUTIONS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_5mnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/enterprise" data-analytics-event="{&quot;action&quot;:&quot;enterprise_platform&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;enterprise_platform_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-stack NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.122.392a1.75 1.75 0 0 1 1.756 0l5.003 2.902c.83.481.83 1.68 0 2.162L8.878 8.358a1.75 1.75 0 0 1-1.756 0L2.119 5.456a1.251 1.251 0 0 1 0-2.162ZM8.125 1.69a.248.248 0 0 0-.25 0l-4.63 2.685 4.63 2.685a.248.248 0 0 0 .25 0l4.63-2.685ZM1.601 7.789a.75.75 0 0 1 1.025-.273l5.249 3.044a.248.248 0 0 0 .25 0l5.249-3.044a.75.75 0 0 1 .752 1.298l-5.248 3.044a1.75 1.75 0 0 1-1.756 0L1.874 8.814A.75.75 0 0 1 1.6 7.789Zm0 3.5a.75.75 0 0 1 1.025-.273l5.249 3.044a.248.248 0 0 0 .25 0l5.249-3.044a.75.75 0 0 1 .752 1.298l-5.248 3.044a1.75 1.75 0 0 1-1.756 0l-5.248-3.044a.75.75 0 0 1-.273-1.025Z"></path></svg>Enterprise platform</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">AI-powered developer platform</span></span></a></li></ul></div></li><li><div class="NavGroup-module__group__W8SqJ"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--monospace___QXHDQ Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavGroup-module__title__Wzxz2" id="_R_9mnd_">AVAILABLE ADD-ONS</span><ul class="NavGroup-module__list__UCOFy" aria-labelledby="_R_9mnd_"><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/security/advanced-security" data-analytics-event="{&quot;action&quot;:&quot;github_advanced_security&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;github_advanced_security_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-shield-check NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m8.533.133 5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667l5.25-1.68a1.748 1.748 0 0 1 1.066 0Zm-.61 1.429.001.001-5.25 1.68a.251.251 0 0 0-.174.237V7c0 1.36.275 2.666 1.057 3.859.784 1.194 2.121 2.342 4.366 3.298a.196.196 0 0 0 .154 0c2.245-.957 3.582-2.103 4.366-3.297C13.225 9.666 13.5 8.358 13.5 7V3.48a.25.25 0 0 0-.174-.238l-5.25-1.68a.25.25 0 0 0-.153 0ZM11.28 6.28l-3.5 3.5a.75.75 0 0 1-1.06 0l-1.5-1.5a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l.97.97 2.97-2.97a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path></svg>GitHub Advanced Security</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enterprise-grade security features</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/features/copilot/copilot-business" data-analytics-event="{&quot;action&quot;:&quot;copilot_for_business&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;copilot_for_business_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copilot NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.998 15.035c-4.562 0-7.873-2.914-7.998-3.749V9.338c.085-.628.677-1.686 1.588-2.065.013-.07.024-.143.036-.218.029-.183.06-.384.126-.612-.201-.508-.254-1.084-.254-1.656 0-.87.128-1.769.693-2.484.579-.733 1.494-1.124 2.724-1.261 1.206-.134 2.262.034 2.944.765.05.053.096.108.139.165.044-.057.094-.112.143-.165.682-.731 1.738-.899 2.944-.765 1.23.137 2.145.528 2.724 1.261.566.715.693 1.614.693 2.484 0 .572-.053 1.148-.254 1.656.066.228.098.429.126.612.012.076.024.148.037.218.924.385 1.522 1.471 1.591 2.095v1.872c0 .766-3.351 3.795-8.002 3.795Zm0-1.485c2.28 0 4.584-1.11 5.002-1.433V7.862l-.023-.116c-.49.21-1.075.291-1.727.291-1.146 0-2.059-.327-2.71-.991A3.222 3.222 0 0 1 8 6.303a3.24 3.24 0 0 1-.544.743c-.65.664-1.563.991-2.71.991-.652 0-1.236-.081-1.727-.291l-.023.116v4.255c.419.323 2.722 1.433 5.002 1.433ZM6.762 2.83c-.193-.206-.637-.413-1.682-.297-1.019.113-1.479.404-1.713.7-.247.312-.369.789-.369 1.554 0 .793.129 1.171.308 1.371.162.181.519.379 1.442.379.853 0 1.339-.235 1.638-.54.315-.322.527-.827.617-1.553.117-.935-.037-1.395-.241-1.614Zm4.155-.297c-1.044-.116-1.488.091-1.681.297-.204.219-.359.679-.242 1.614.091.726.303 1.231.618 1.553.299.305.784.54 1.638.54.922 0 1.28-.198 1.442-.379.179-.2.308-.578.308-1.371 0-.765-.123-1.242-.37-1.554-.233-.296-.693-.587-1.713-.7Z"></path><path d="M6.25 9.037a.75.75 0 0 1 .75.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 .75-.75Zm4.25.75v1.501a.75.75 0 0 1-1.5 0V9.787a.75.75 0 0 1 1.5 0Z"></path></svg>Copilot for Business</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enterprise-grade AI features</span></span></a></li><li><a class="Primer_Brand__Link-module__Link___lF11y Primer_Brand__Link-module__Link--default___VRVW0 NavLink-module__link__EG3d4" href="https://github.com/enterprise/premium-support" data-analytics-event="{&quot;action&quot;:&quot;premium_support&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;enterprise&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;premium_support_link_enterprise_navbar&quot;}"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Link-module__Link--label___jM8Ty"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS Primer_Brand__Text-module__Text--weight-medium___qJKf_ NavLink-module__title__Q7t0p"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-comment-discussion NavLink-module__icon__ltGNM" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z"></path></svg>Premium Support</span><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--muted___rE6mh Primer_Brand__Text-module__Text--200____P1wy Primer_Brand__Text-module__Text--antialiased___TYoXS NavLink-module__subtitle__X4gkW">Enterprise-grade 24/7 support</span></span></a></li></ul></div></li></ul></div></div></li><li><a href="https://github.com/pricing" data-analytics-event="{&quot;action&quot;:&quot;pricing&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;pricing&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;pricing_link_pricing_navbar&quot;}" class="MarketingNavigation-module__navLink__hUomM">Pricing</a></li></ul></nav><div class="MarketingHeader-module__ctaContainer__tBmPz"><div class="HeaderSearch-module__searchSlot__oVOUS"><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw HeaderSearch-module__trigger__zsF9q" type="button" aria-haspopup="dialog" aria-expanded="false" aria-label="Search or jump to, type / to search" data-analytics-event="{&quot;action&quot;:&quot;searchbar&quot;,&quot;tag&quot;:&quot;input&quot;,&quot;context&quot;:&quot;global&quot;,&quot;location&quot;:&quot;navbar&quot;,&quot;label&quot;:&quot;searchbar_input_global_navbar&quot;}"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH"><span class="HeaderSearch-module__content__kMpxU"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-search HeaderSearch-module__icon__wcrHX" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path></svg><span class="HeaderSearch-module__label__d1iWG">Search</span><kbd class="HeaderSearch-module__kbd__HNG0o" aria-hidden="true">/</kbd></span></span></span></button><div class="d-none"></div></div><div class="AuthCTAs-module__signInWrap__q2P60"><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw AuthCTAs-module__cta__WpwQq AuthCTAs-module__desktopActionGap__UZuXT AuthCTAs-module__hiddenBelowLg__BfKBw" href="/login?return_to=https%3A%2F%2Fgithub.com%2Fcht37%2FJavaGuide%2Fblob%2Fmain%2Fdocs%2Fjava%2Fcollection%2Farrayblockingqueue-source-code.md" data-analytics-event="{&quot;action&quot;:&quot;sign_in&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;auth_cta&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;sign_in_link_auth_cta_header&quot;}" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/cht37/JavaGuide/blob/main/docs/java/collection/arrayblockingqueue-source-code.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="cdabdc98c705ecb274e2c9b18b2adec933089ca950627aa4689b63cde73f6152"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH">Sign in</span></span></a></div><a class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--secondary___gHnw_ Primer_Brand__Button-module__Button--size-small___zQrEw AuthCTAs-module__cta__WpwQq" href="/signup?ref_cta=Sign+up&amp;ref_loc=header+logged+out&amp;ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fblob%2Fshow&amp;source=header-repo&amp;source_repo=cht37%2FJavaGuide" data-analytics-event="{&quot;action&quot;:&quot;sign_up&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;context&quot;:&quot;auth_cta&quot;,&quot;location&quot;:&quot;header&quot;,&quot;label&quot;:&quot;sign_up_link_auth_cta_header&quot;}" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;site header menu&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://github.com/cht37/JavaGuide/blob/main/docs/java/collection/arrayblockingqueue-source-code.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="cdabdc98c705ecb274e2c9b18b2adec933089ca950627aa4689b63cde73f6152"><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-secondary___eJ0_a">Sign up</span></span></a><button class="Primer_Brand__Button-module__Button___scH9Z Primer_Brand__Button-module__Button--subtle___F7pEE Primer_Brand__Button-module__Button--size-small___zQrEw HeaderAppearanceSettings-module__trigger__hUheK" type="button" aria-haspopup="dialog" aria-labelledby="_R_fbd_"><span class="Primer_Brand__Button-module__Button__leading-visual___jjtTe" data-testid="Button-leading-visual"><svg data-component="Octicon" focusable="false" aria-hidden="true" class="octicon octicon-sliders Primer_Brand__Button-module__Button__icon-visual____qybb" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M15 2.75a.75.75 0 0 1-.75.75h-4a.75.75 0 0 1 0-1.5h4a.75.75 0 0 1 .75.75Zm-8.5.75v1.25a.75.75 0 0 0 1.5 0v-4a.75.75 0 0 0-1.5 0V2H1.75a.75.75 0 0 0 0 1.5H6.5Zm1.25 5.25a.75.75 0 0 0 0-1.5h-6a.75.75 0 0 0 0 1.5h6ZM15 8a.75.75 0 0 1-.75.75H11.5V10a.75.75 0 1 1-1.5 0V6a.75.75 0 0 1 1.5 0v1.25h2.75A.75.75 0 0 1 15 8Zm-9 5.25v-2a.75.75 0 0 0-1.5 0v1.25H1.75a.75.75 0 0 0 0 1.5H4.5v1.25a.75.75 0 0 0 1.5 0v-2Zm9 0a.75.75 0 0 1-.75.75h-6a.75.75 0 0 1 0-1.5h6a.75.75 0 0 1 .75.75Z"></path></svg></span><span class="Primer_Brand__Button-module__Button__text___ED0bX"><span class="Primer_Brand__Text-module__Text___XeGJJ Primer_Brand__Text-module__Text-font--mona-sans___a8XJD Primer_Brand__Text-module__Text--default___GhPh_ Primer_Brand__Text-module__Text--100___B2ueX Primer_Brand__Text-module__Text--weight-medium___qJKf_ Primer_Brand__Button-module__Button--label___qrkyz Primer_Brand__Button-module__Button--label-subtle___8ndWH"></span></span></button><div class="Primer_Brand__Tooltip-module__Tooltip___0Eipx" data-direction="s" aria-hidden="true" id="_R_fbd_">Appearance settings</div></div></div></div></div><div class="MarketingHeader-module__bottomBorder__uZT38" aria-hidden="true"></div></header></div></div>
</react-partial>



      <div hidden="hidden" data-view-component="true" class="js-stale-session-flash stale-session-flash flash flash-warn flash-full">
  
        <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert">
    <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
</svg>
        <span class="js-stale-session-flash-signed-in" hidden>You signed in with another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span>
        <span class="js-stale-session-flash-signed-out" hidden>You signed out in another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span>
        <span class="js-stale-session-flash-switched" hidden>You switched accounts on another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span>

    <button id="icon-button-4cb49997-3459-4b59-a246-664baea8477a" aria-labelledby="tooltip-fd85e521-8508-4560-b131-7fd41e04607c" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium flash-close js-flash-close">  <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x Button-visual">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
</button><tool-tip id="tooltip-fd85e521-8508-4560-b131-7fd41e04607c" for="icon-button-4cb49997-3459-4b59-a246-664baea8477a" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Dismiss alert</tool-tip>


  
</div>
    </div>

  <div id="start-of-content" class="show-on-focus"></div>








    <div id="js-flash-container" class="flash-container" data-turbo-replace>





  <template class="js-flash-template">
    
<div class="flash flash-full   {{ className }}">
  <div >
    <button autofocus class="flash-close js-flash-close" type="button" aria-label="Dismiss this message">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
    </button>
    <div aria-atomic="true" role="alert" class="js-flash-alert">
      
      <div>{{ message }}</div>

    </div>
  </div>
</div>
  </template>
</div>


    






  <div
    class="application-main "
    data-commit-hovercards-enabled
    data-discussion-hovercards-enabled
    data-issue-and-pr-hovercards-enabled
    data-project-hovercards-enabled
  >
        <div itemscope itemtype="http://schema.org/SoftwareSourceCode" class="">
    <main id="js-repo-pjax-container" >
      
      








  

    <div id="repository-container-header"  class="tmp-pt-3 hide-full-screen" style="background-color: var(--page-header-bgColor, var(--color-page-header-bg));" data-turbo-replace>

        <div class="d-flex flex-nowrap flex-justify-end tmp-mb-3  tmp-px-3 tmp-px-lg-5" style="gap: 1rem;">

          <div class="flex-auto min-width-0 width-fit">
              
  <div class=" d-flex flex-wrap flex-items-center wb-break-word f3 text-normal">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked color-fg-muted mr-2 tmp-mr-2">
    <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path>
</svg>
    
    <span class="author flex-self-stretch" itemprop="author">
      <a class="url fn" rel="author" data-hovercard-type="user" data-hovercard-url="/users/cht37/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/cht37">
        cht37
</a>    </span>
    <span class="mx-1 flex-self-stretch color-fg-muted">/</span>
    <strong itemprop="name" class="mr-2 flex-self-stretch">
      <a data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" href="/cht37/JavaGuide">JavaGuide</a>
    </strong>

    <span></span><span class="Label Label--secondary v-align-middle mr-1">Public</span>
  </div>
    <span class="text-small lh-condensed-ultra no-wrap mt-1" data-repository-hovercards-enabled>
      forked from <a data-hovercard-type="repository" data-hovercard-url="/Snailclimb/JavaGuide/hovercard" class="Link--inTextBlock" href="/Snailclimb/JavaGuide">Snailclimb/JavaGuide</a>
    </span>


          </div>

          <div id="repository-details-container" class="flex-shrink-0" data-turbo-replace style="max-width: 70%;">
              <ul class="pagehead-actions flex-shrink-0 d-none d-md-inline" style="padding: 2px 0;">
    
      

  <li>
            <a href="/login?return_to=%2Fcht37%2FJavaGuide" rel="nofollow" id="repository-details-watch-button" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;notification subscription menu watch&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://github.com/cht37/JavaGuide/blob/main/docs/java/collection/arrayblockingqueue-source-code.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="61ab33f2587c83f3ce9cbbd3b0b6e01a24ae4bf666021c0c69dac8df79bb6b36" aria-label="You must be signed in to change notification settings" data-view-component="true" class="btn-sm btn">    <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-bell mr-2 tmp-mr-2">
    <path d="M8 16a2 2 0 0 0 1.985-1.75c.017-.137-.097-.25-.235-.25h-3.5c-.138 0-.252.113-.235.25A2 2 0 0 0 8 16ZM3 5a5 5 0 0 1 10 0v2.947c0 .05.015.098.042.139l1.703 2.555A1.519 1.519 0 0 1 13.482 13H2.518a1.516 1.516 0 0 1-1.263-2.36l1.703-2.554A.255.255 0 0 0 3 7.947Zm5-3.5A3.5 3.5 0 0 0 4.5 5v2.947c0 .346-.102.683-.294.97l-1.703 2.556a.017.017 0 0 0-.003.01l.001.006c0 .002.002.004.004.006l.006.004.007.001h10.964l.007-.001.006-.004.004-.006.001-.007a.017.017 0 0 0-.003-.01l-1.703-2.554a1.745 1.745 0 0 1-.294-.97V5A3.5 3.5 0 0 0 8 1.5Z"></path>
</svg>Notifications
</a>    <tool-tip id="tooltip-bbb0a058-4b77-41c4-a46d-3883f3b3d186" for="repository-details-watch-button" popover="manual" data-direction="s" data-type="description" data-view-component="true" class="sr-only position-absolute">You must be signed in to change notification settings</tool-tip>

  </li>

  <li>
          <a icon="repo-forked" id="fork-button" href="/login?return_to=%2Fcht37%2FJavaGuide" rel="nofollow" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;repo details fork button&quot;,&quot;repository_id&quot;:758919476,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://github.com/cht37/JavaGuide/blob/main/docs/java/collection/arrayblockingqueue-source-code.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="7bceca7306b91c29f0e457ba7b38d59dd08d1f8e6ae63238401e5362f99383ad" data-view-component="true" class="btn-sm btn">    <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked mr-2 tmp-mr-2">
    <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path>
</svg>Fork
    <span id="repo-network-counter" data-pjax-replace="true" data-turbo-replace="true" title="0" data-view-component="true" class="Counter">0</span>
</a>
  </li>

  <li>
        <div data-view-component="true" class="BtnGroup d-flex">
        <a href="/login?return_to=%2Fcht37%2FJavaGuide" rel="nofollow" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;star button&quot;,&quot;repository_id&quot;:758919476,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://github.com/cht37/JavaGuide/blob/main/docs/java/collection/arrayblockingqueue-source-code.md&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="85e66e1aa98d6153bf33ebc081e73e410b27f6fa9533819fac39873ee83e4a1b" aria-label="You must be signed in to star a repository" data-view-component="true" class="tooltipped tooltipped-sw btn-sm btn">    <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star v-align-text-bottom d-inline-block mr-2 tmp-mr-2">
    <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path>
</svg><span data-view-component="true" class="d-inline">
          Star
</span>          <span id="repo-stars-counter-star" aria-label="0 users starred this repository" data-singular-suffix="user starred this repository" data-plural-suffix="users starred this repository" data-turbo-replace="true" title="0" data-view-component="true" class="Counter js-social-count">0</span>
</a></div>
  </li>

</ul>

          </div>
        </div>

          <div id="responsive-meta-container" data-turbo-replace>
</div>


            <nav data-pjax="#js-repo-pjax-container" aria-label="Repository" data-view-component="true" class="js-repo-nav js-sidenav-container-pjax js-responsive-underlinenav overflow-hidden UnderlineNav px-3 tmp-px-3 px-md-4 tmp-px-md-4 px-lg-5 tmp-px-lg-5">

  <ul data-view-component="true" class="UnderlineNav-body list-style-none">
      <li data-view-component="true" class="d-inline-flex">
  <a id="code-tab" href="/cht37/JavaGuide" data-tab-item="i0code-tab" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches repo_packages repo_deployments repo_attestations /cht37/JavaGuide" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g c" data-command-id="repositories:go-to-code" data-react-nav="code-view" data-react-nav-anchor="code-view-repo-link" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Code&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" aria-current="page" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item selected">
    
              <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code UnderlineNav-octicon d-none d-sm-inline">
    <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path>
</svg>
        <span data-content="Code">Code</span>
          <span id="code-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span>


    
</a></li>
      <li data-view-component="true" class="d-inline-flex">
  <a id="pull-requests-tab" href="/cht37/JavaGuide/pulls" data-tab-item="i1pull-requests-tab" data-selected-links="repo_pulls checks /cht37/JavaGuide/pulls" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g p" data-command-id="repositories:go-to-pull-requests" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Pull requests&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item">
    
              <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-pull-request UnderlineNav-octicon d-none d-sm-inline">
    <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path>
</svg>
        <span data-content="Pull requests">Pull requests</span>
          <span id="pull-requests-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="0" hidden="hidden" data-view-component="true" class="Counter">0</span>


    
</a></li>
      <li data-view-component="true" class="d-inline-flex">
  <a id="actions-tab" href="/cht37/JavaGuide/actions" data-tab-item="i2actions-tab" data-selected-links="repo_actions /cht37/JavaGuide/actions" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g a" data-command-id="repositories:go-to-actions" data-react-nav="actions-workflows" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Actions&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item">
    
              <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play UnderlineNav-octicon d-none d-sm-inline">
    <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path>
</svg>
        <span data-content="Actions">Actions</span>
          <span id="actions-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span>


    
</a></li>
      <li data-view-component="true" class="d-inline-flex">
  <a id="projects-tab" href="/cht37/JavaGuide/projects" data-tab-item="i3projects-tab" data-selected-links="repo_projects new_repo_project repo_project /cht37/JavaGuide/projects" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g b" data-command-id="repositories:go-to-projects" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Projects&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item">
    
              <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-table UnderlineNav-octicon d-none d-sm-inline">
    <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM6.5 6.5v8h7.75a.25.25 0 0 0 .25-.25V6.5Zm8-1.5V1.75a.25.25 0 0 0-.25-.25H6.5V5Zm-13 1.5v7.75c0 .138.112.25.25.25H5v-8ZM5 5V1.5H1.75a.25.25 0 0 0-.25.25V5Z"></path>
</svg>
        <span data-content="Projects">Projects</span>
          <span id="projects-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span>


    
</a></li>
      <li data-view-component="true" class="d-inline-flex">
  <a id="security-and-quality-tab" href="/cht37/JavaGuide/security" data-tab-item="i4security-and-quality-tab" data-selected-links="security overview alerts policy token_scanning code_scanning /cht37/JavaGuide/security" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-hotkey="g s" data-command-id="repositories:go-to-security" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Security and quality&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item">
    
              <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield UnderlineNav-octicon d-none d-sm-inline">
    <path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
</svg>
        <span data-content="Security and quality">Security and quality</span>
          <span id="security-and-quality-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="0" hidden="hidden" data-view-component="true" class="Counter">0</span>


    
</a></li>
      <li data-view-component="true" class="d-inline-flex">
  <a id="insights-tab" href="/cht37/JavaGuide/pulse" data-tab-item="i5insights-tab" data-selected-links="repo_graphs repo_contributors dependency_graph dependabot_updates pulse people community /cht37/JavaGuide/pulse" data-pjax="#repo-content-pjax-container" data-turbo-frame="repo-content-turbo-frame" data-command-id="repositories:go-to-insights" data-analytics-event="{&quot;category&quot;:&quot;Underline navbar&quot;,&quot;action&quot;:&quot;Click tab&quot;,&quot;label&quot;:&quot;Insights&quot;,&quot;target&quot;:&quot;UNDERLINE_NAV.TAB&quot;}" data-view-component="true" class="UnderlineNav-item no-wrap js-responsive-underlinenav-item js-selected-navigation-item">
    
              <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-graph UnderlineNav-octicon d-none d-sm-inline">
    <path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path>
</svg>
        <span data-content="Insights">Insights</span>
          <span id="insights-repo-tab-count" data-pjax-replace="" data-turbo-replace="" title="Not available" data-view-component="true" class="Counter"></span>


    
</a></li>
</ul>
    <div style="visibility:hidden;" data-view-component="true" class="UnderlineNav-actions js-responsive-underlinenav-overflow position-absolute pr-3 tmp-pr-3 pr-md-4 tmp-pr-md-4 pr-lg-5 tmp-pr-lg-5 right-0">      <action-menu data-select-variant="none" data-view-component="true">
  <focus-group direction="vertical" mnemonics retain>
    <button id="action-menu-9e74b993-5a76-478c-b250-42a1dd116072-button" popovertarget="action-menu-9e74b993-5a76-478c-b250-42a1dd116072-overlay" aria-controls="action-menu-9e74b993-5a76-478c-b250-42a1dd116072-list" aria-haspopup="true" aria-labelledby="tooltip-f5520bd4-e964-4c4f-9867-1c4af9410709" type="button" data-view-component="true" class="Button Button--iconOnly Button--secondary Button--medium UnderlineNav-item">  <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal Button-visual">
    <path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path>
</svg>
</button><tool-tip id="tooltip-f5520bd4-e964-4c4f-9867-1c4af9410709" for="action-menu-9e74b993-5a76-478c-b250-42a1dd116072-button" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Additional navigation options</tool-tip>


<anchored-position data-target="action-menu.overlay" id="action-menu-9e74b993-5a76-478c-b250-42a1dd116072-overlay" anchor="action-menu-9e74b993-5a76-478c-b250-42a1dd116072-button" align="start" side="outside-bottom" anchor-offset="normal" popover="auto" data-view-component="true">
  <div data-view-component="true" class="Overlay Overlay--size-auto">
    
      <div data-view-component="true" class="Overlay-body Overlay-body--paddingNone">          <action-list>
  <div data-view-component="true">
    <ul aria-labelledby="action-menu-9e74b993-5a76-478c-b250-42a1dd116072-button" id="action-menu-9e74b993-5a76-478c-b250-42a1dd116072-list" role="menu" data-view-component="true" class="ActionListWrap--inset ActionListWrap">
        <li hidden="hidden" data-menu-item="i0code-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem">
    
    
    <a tabindex="-1" id="item-c1949597-0d8a-4716-98b2-7dbdf10f892b" href="/cht37/JavaGuide" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
        <span class="ActionListItem-visual ActionListItem-visual--leading">
          <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code">
    <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path>
</svg>
        </span>
      
        <span data-view-component="true" class="ActionListItem-label">
          Code
</span>      
</a>
  
</li>
        <li hidden="hidden" data-menu-item="i1pull-requests-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem">
    
    
    <a tabindex="-1" id="item-7c6c3177-0ab0-4b92-ba41-4b805e9bb123" href="/cht37/JavaGuide/pulls" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
        <span class="ActionListItem-visual ActionListItem-visual--leading">
          <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-pull-request">
    <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm8.25.75a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Z"></path>
</svg>
        </span>
      
        <span data-view-component="true" class="ActionListItem-label">
          Pull requests
</span>      
</a>
  
</li>
        <li hidden="hidden" data-menu-item="i2actions-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem">
    
    
    <a tabindex="-1" id="item-938db459-cf0c-4eb8-9255-91ed5437c00d" href="/cht37/JavaGuide/actions" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
        <span class="ActionListItem-visual ActionListItem-visual--leading">
          <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-play">
    <path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0ZM1.5 8a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0Zm4.879-2.773 4.264 2.559a.25.25 0 0 1 0 .428l-4.264 2.559A.25.25 0 0 1 6 10.559V5.442a.25.25 0 0 1 .379-.215Z"></path>
</svg>
        </span>
      
        <span data-view-component="true" class="ActionListItem-label">
          Actions
</span>      
</a>
  
</li>
        <li hidden="hidden" data-menu-item="i3projects-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem">
    
    
    <a tabindex="-1" id="item-ce52b7bf-2be1-4e8b-aa0f-d7a8c98f79e8" href="/cht37/JavaGuide/projects" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
        <span class="ActionListItem-visual ActionListItem-visual--leading">
          <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-table">
    <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25ZM6.5 6.5v8h7.75a.25.25 0 0 0 .25-.25V6.5Zm8-1.5V1.75a.25.25 0 0 0-.25-.25H6.5V5Zm-13 1.5v7.75c0 .138.112.25.25.25H5v-8ZM5 5V1.5H1.75a.25.25 0 0 0-.25.25V5Z"></path>
</svg>
        </span>
      
        <span data-view-component="true" class="ActionListItem-label">
          Projects
</span>      
</a>
  
</li>
        <li hidden="hidden" data-menu-item="i4security-and-quality-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem">
    
    
    <a tabindex="-1" id="item-3b617768-832e-4ca5-af1e-3d22bf10820c" href="/cht37/JavaGuide/security" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
        <span class="ActionListItem-visual ActionListItem-visual--leading">
          <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-shield">
    <path d="M7.467.133a1.748 1.748 0 0 1 1.066 0l5.25 1.68A1.75 1.75 0 0 1 15 3.48V7c0 1.566-.32 3.182-1.303 4.682-.983 1.498-2.585 2.813-5.032 3.855a1.697 1.697 0 0 1-1.33 0c-2.447-1.042-4.049-2.357-5.032-3.855C1.32 10.182 1 8.566 1 7V3.48a1.75 1.75 0 0 1 1.217-1.667Zm.61 1.429a.25.25 0 0 0-.153 0l-5.25 1.68a.25.25 0 0 0-.174.238V7c0 1.358.275 2.666 1.057 3.86.784 1.194 2.121 2.34 4.366 3.297a.196.196 0 0 0 .154 0c2.245-.956 3.582-2.104 4.366-3.298C13.225 9.666 13.5 8.36 13.5 7V3.48a.251.251 0 0 0-.174-.237l-5.25-1.68ZM8.75 4.75v3a.75.75 0 0 1-1.5 0v-3a.75.75 0 0 1 1.5 0ZM9 10.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
</svg>
        </span>
      
        <span data-view-component="true" class="ActionListItem-label">
          Security and quality
</span>      
</a>
  
</li>
        <li hidden="hidden" data-menu-item="i5insights-tab" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem">
    
    
    <a tabindex="-1" id="item-89f39c88-14e6-4c30-927e-d1df96cfc072" href="/cht37/JavaGuide/pulse" role="menuitem" data-view-component="true" class="ActionListContent ActionListContent--visual16">
        <span class="ActionListItem-visual ActionListItem-visual--leading">
          <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-graph">
    <path d="M1.5 1.75V13.5h13.75a.75.75 0 0 1 0 1.5H.75a.75.75 0 0 1-.75-.75V1.75a.75.75 0 0 1 1.5 0Zm14.28 2.53-5.25 5.25a.75.75 0 0 1-1.06 0L7 7.06 4.28 9.78a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042l3.25-3.25a.75.75 0 0 1 1.06 0L10 7.94l4.72-4.72a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path>
</svg>
        </span>
      
        <span data-view-component="true" class="ActionListItem-label">
          Insights
</span>      
</a>
  
</li>
</ul>    
</div></action-list>


</div>
      
</div></anchored-position>  </focus-group>
</action-menu></div>
</nav>

    </div>
  



<turbo-frame id="repo-content-turbo-frame" target="_top" data-turbo-action="advance" class="">
    <div id="repo-content-pjax-container" class="repository-content " >
    



    
      
    








<react-app
  app-name="code-view"
  initial-path="/cht37/JavaGuide/blob/main/docs/java/collection/arrayblockingqueue-source-code.md"
  style="display: block; min-height: calc(100vh - 64px);"
  data-attempted-ssr="true"
  data-ssr="true"
  data-lazy="false"
  data-alternate="false"
  data-data-router-enabled="true"
  data-react-profiling="false"
>
  
  <script type="application/json" data-target="react-app.embeddedData">{"payload":{"codeViewBlobRoute":{"csv":null,"csvError":null,"headerInfo":{"toc":[{"level":2,"text":"阻塞队列简介","anchor":"阻塞队列简介","htmlText":"阻塞队列简介"},{"level":3,"text":"阻塞队列的历史","anchor":"阻塞队列的历史","htmlText":"阻塞队列的历史"},{"level":3,"text":"阻塞队列的思想","anchor":"阻塞队列的思想","htmlText":"阻塞队列的思想"},{"level":2,"text":"ArrayBlockingQueue 常见方法及测试","anchor":"arrayblockingqueue-常见方法及测试","htmlText":"ArrayBlockingQueue 常见方法及测试"},{"level":2,"text":"ArrayBlockingQueue 源码分析","anchor":"arrayblockingqueue-源码分析","htmlText":"ArrayBlockingQueue 源码分析"},{"level":3,"text":"整体设计","anchor":"整体设计","htmlText":"整体设计"},{"level":3,"text":"初始化","anchor":"初始化","htmlText":"初始化"},{"level":3,"text":"阻塞式获取和新增元素","anchor":"阻塞式获取和新增元素","htmlText":"阻塞式获取和新增元素"},{"level":3,"text":"非阻塞式获取和新增元素","anchor":"非阻塞式获取和新增元素","htmlText":"非阻塞式获取和新增元素"},{"level":3,"text":"指定超时时间内阻塞式获取和新增元素","anchor":"指定超时时间内阻塞式获取和新增元素","htmlText":"指定超时时间内阻塞式获取和新增元素"},{"level":3,"text":"判断元素是否存在","anchor":"判断元素是否存在","htmlText":"判断元素是否存在"},{"level":2,"text":"ArrayBlockingQueue 获取和新增元素的方法对比","anchor":"arrayblockingqueue-获取和新增元素的方法对比","htmlText":"ArrayBlockingQueue 获取和新增元素的方法对比"},{"level":2,"text":"ArrayBlockingQueue 相关面试题","anchor":"arrayblockingqueue-相关面试题","htmlText":"ArrayBlockingQueue 相关面试题"},{"level":3,"text":"ArrayBlockingQueue 是什么？它的特点是什么？","anchor":"arrayblockingqueue-是什么它的特点是什么","htmlText":"ArrayBlockingQueue 是什么？它的特点是什么？"},{"level":3,"text":"ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别？","anchor":"arrayblockingqueue-和-linkedblockingqueue-有什么区别","htmlText":"ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别？"},{"level":3,"text":"ArrayBlockingQueue 和 ConcurrentLinkedQueue 有什么区别？","anchor":"arrayblockingqueue-和-concurrentlinkedqueue-有什么区别","htmlText":"ArrayBlockingQueue 和 ConcurrentLinkedQueue 有什么区别？"},{"level":3,"text":"ArrayBlockingQueue 的实现原理是什么？","anchor":"arrayblockingqueue-的实现原理是什么","htmlText":"ArrayBlockingQueue 的实现原理是什么？"},{"level":2,"text":"参考文献","anchor":"参考文献","htmlText":"参考文献"}]},"issueTemplate":null,"discussionTemplate":null,"richText":"\u003carticle class=\"markdown-body entry-content container-lg\" itemprop=\"text\"\u003e\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n  \u003ctbody\u003e\n  \u003ctr\u003e\n    \u003cth\u003etitle\u003c/th\u003e\n    \u003ctd\u003eArrayBlockingQueue 源码分析\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003cth\u003ecategory\u003c/th\u003e\n    \u003ctd\u003eJava\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003cth\u003etag\u003c/th\u003e\n    \u003ctd\u003e\u003ctable\u003e\n  \u003ctbody\u003e\n  \u003ctr\u003e\n  \u003ctd\u003e\u003cdiv dir=\"auto\"\u003eJava集合\u003c/div\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e阻塞队列简介\u003c/h2\u003e\u003ca id=\"user-content-阻塞队列简介\" class=\"anchor\" aria-label=\"Permalink: 阻塞队列简介\" href=\"#阻塞队列简介\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e阻塞队列的历史\u003c/h3\u003e\u003ca id=\"user-content-阻塞队列的历史\" class=\"anchor\" aria-label=\"Permalink: 阻塞队列的历史\" href=\"#阻塞队列的历史\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eJava 阻塞队列的历史可以追溯到 JDK1.5 版本，当时 Java 平台增加了 \u003ccode\u003ejava.util.concurrent\u003c/code\u003e，即我们常说的 JUC 包，其中包含了各种并发流程控制工具、并发容器、原子类等。这其中自然也包含了我们这篇文章所讨论的阻塞队列。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e为了解决高并发场景下多线程之间数据共享的问题，JDK1.5 版本中出现了 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 和 \u003ccode\u003eLinkedBlockingQueue\u003c/code\u003e，它们是带有生产者-消费者模式实现的并发容器。其中，\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 是有界队列，即添加的元素达到上限之后，再次添加就会被阻塞或者抛出异常。而 \u003ccode\u003eLinkedBlockingQueue\u003c/code\u003e 则由链表构成的队列，正是因为链表的特性，所以 \u003ccode\u003eLinkedBlockingQueue\u003c/code\u003e 在添加元素上并不会向 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 那样有着较多的约束，所以 \u003ccode\u003eLinkedBlockingQueue\u003c/code\u003e 设置队列是否有界是可选的(注意这里的无界并不是指可以添加任务数量的元素，而是说队列的大小默认为 \u003ccode\u003eInteger.MAX_VALUE\u003c/code\u003e，近乎于无限大)。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e随着 Java 的不断发展，JDK 后续的几个版本又对阻塞队列进行了不少的更新和完善:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003eJDK1.6 版本:增加 \u003ccode\u003eSynchronousQueue\u003c/code\u003e，一个不存储元素的阻塞队列。\u003c/li\u003e\n\u003cli\u003eJDK1.7 版本:增加 \u003ccode\u003eTransferQueue\u003c/code\u003e，一个支持更多操作的阻塞队列。\u003c/li\u003e\n\u003cli\u003eJDK1.8 版本:增加 \u003ccode\u003eDelayQueue\u003c/code\u003e，一个支持延迟获取元素的阻塞队列。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e阻塞队列的思想\u003c/h3\u003e\u003ca id=\"user-content-阻塞队列的思想\" class=\"anchor\" aria-label=\"Permalink: 阻塞队列的思想\" href=\"#阻塞队列的思想\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e阻塞队列就是典型的生产者-消费者模型，它可以做到以下几点:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e当阻塞队列数据为空时，所有的消费者线程都会被阻塞，等待队列非空。\u003c/li\u003e\n\u003cli\u003e当生产者往队列里填充数据后，队列就会通知消费者队列非空，消费者此时就可以进来消费。\u003c/li\u003e\n\u003cli\u003e当阻塞队列因为消费者消费过慢或者生产者存放元素过快导致队列填满时无法容纳新元素时，生产者就会被阻塞，等待队列非满时继续存放元素。\u003c/li\u003e\n\u003cli\u003e当消费者从队列中消费一个元素之后，队列就会通知生产者队列非满，生产者可以继续填充数据了。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp dir=\"auto\"\u003e总结一下：阻塞队列就说基于非空和非满两个条件实现生产者和消费者之间的交互，尽管这些交互流程和等待通知的机制实现非常复杂，好在 Doug Lea 的操刀之下已将阻塞队列的细节屏蔽，我们只需调用 \u003ccode\u003eput\u003c/code\u003e、\u003ccode\u003etake\u003c/code\u003e、\u003ccode\u003eofffer\u003c/code\u003e、\u003ccode\u003epoll\u003c/code\u003e 等 API 即可实现多线程之间的生产和消费。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e这也使得阻塞队列在多线程开发中有着广泛的运用，最常见的例子无非是我们的线程池,从源码中我们就能看出当核心线程无法及时处理任务时，这些任务都会扔到 \u003ccode\u003eworkQueue\u003c/code\u003e 中。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public ThreadPoolExecutor(int corePoolSize,\n                            int maximumPoolSize,\n                            long keepAliveTime,\n                            TimeUnit unit,\n                            BlockingQueue\u0026lt;Runnable\u0026gt; workQueue,\n                            ThreadFactory threadFactory,\n                            RejectedExecutionHandler handler) {// ...}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eThreadPoolExecutor\u003c/span\u003e\u003cspan class=\"pl-en\"\u003e\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ecorePoolSize\u003c/span\u003e,\n                            \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003emaximumPoolSize\u003c/span\u003e,\n                            \u003cspan class=\"pl-smi\"\u003elong\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ekeepAliveTime\u003c/span\u003e,\n                            \u003cspan class=\"pl-smi\"\u003eTimeUnit\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eunit\u003c/span\u003e,\n                            \u003cspan class=\"pl-smi\"\u003eBlockingQueue\u003c/span\u003e\u0026lt;\u003cspan class=\"pl-smi\"\u003eRunnable\u003c/span\u003e\u0026gt; \u003cspan class=\"pl-s1\"\u003eworkQueue\u003c/span\u003e,\n                            \u003cspan class=\"pl-smi\"\u003eThreadFactory\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ethreadFactory\u003c/span\u003e,\n                            \u003cspan class=\"pl-smi\"\u003eRejectedExecutionHandler\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ehandler\u003c/span\u003e) {\u003cspan class=\"pl-c\"\u003e// ...}\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eArrayBlockingQueue 常见方法及测试\u003c/h2\u003e\u003ca id=\"user-content-arrayblockingqueue-常见方法及测试\" class=\"anchor\" aria-label=\"Permalink: ArrayBlockingQueue 常见方法及测试\" href=\"#arrayblockingqueue-常见方法及测试\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e简单了解了阻塞队列的历史之后，我们就开始重点讨论本篇文章所要介绍的并发容器——\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e。为了后续更加深入的了解 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e，我们不妨基于下面几个实例了解以下 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 的使用。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e先看看第一个例子，我们这里会用两个线程分别模拟生产者和消费者，生产者生产完会使用 \u003ccode\u003eput\u003c/code\u003e 方法生产 10 个元素给消费者进行消费，当队列元素达到我们设置的上限 5 时，\u003ccode\u003eput\u003c/code\u003e 方法就会阻塞。\n同理消费者也会通过 \u003ccode\u003etake\u003c/code\u003e 方法消费元素，当队列为空时，\u003ccode\u003etake\u003c/code\u003e 方法就会阻塞消费者线程。这里笔者为了保证消费者能够在消费完 10 个元素后及时退出。便通过倒计时门闩，来控制消费者结束，生产者在这里只会生产 10 个元素。当消费者将 10 个元素消费完成之后，按下倒计时门闩，所有线程都会停止。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public class ProducerConsumerExample {\n\n    public static void main(String[] args) throws InterruptedException {\n\n        // 创建一个大小为 5 的 ArrayBlockingQueue\n        ArrayBlockingQueue\u0026lt;Integer\u0026gt; queue = new ArrayBlockingQueue\u0026lt;\u0026gt;(5);\n\n        // 创建生产者线程\n        Thread producer = new Thread(() -\u0026gt; {\n            try {\n                for (int i = 1; i \u0026lt;= 10; i++) {\n                    // 向队列中添加元素，如果队列已满则阻塞等待\n                    queue.put(i);\n                    System.out.println(\u0026quot;生产者添加元素：\u0026quot; + i);\n                }\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n\n        });\n\n        CountDownLatch countDownLatch = new CountDownLatch(1);\n\n        // 创建消费者线程\n        Thread consumer = new Thread(() -\u0026gt; {\n            try {\n                int count = 0;\n                while (true) {\n\n                    // 从队列中取出元素，如果队列为空则阻塞等待\n                    int element = queue.take();\n                    System.out.println(\u0026quot;消费者取出元素：\u0026quot; + element);\n                    ++count;\n                    if (count == 10) {\n                        break;\n                    }\n                }\n\n                countDownLatch.countDown();\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n\n        });\n\n        // 启动线程\n        producer.start();\n        consumer.start();\n\n        // 等待线程结束\n        producer.join();\n        consumer.join();\n\n        countDownLatch.await();\n\n        producer.interrupt();\n        consumer.interrupt();\n    }\n\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eProducerConsumerExample\u003c/span\u003e {\n\n    \u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003estatic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e \u003cspan class=\"pl-en\"\u003emain\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e[] \u003cspan class=\"pl-s1\"\u003eargs\u003c/span\u003e) \u003cspan class=\"pl-k\"\u003ethrows\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eInterruptedException\u003c/span\u003e {\n\n        \u003cspan class=\"pl-c\"\u003e// 创建一个大小为 5 的 ArrayBlockingQueue\u003c/span\u003e\n        \u003cspan class=\"pl-smi\"\u003eArrayBlockingQueue\u003c/span\u003e\u0026lt;\u003cspan class=\"pl-smi\"\u003eInteger\u003c/span\u003e\u0026gt; \u003cspan class=\"pl-s1\"\u003equeue\u003c/span\u003e = \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eArrayBlockingQueue\u003c/span\u003e\u0026lt;\u0026gt;(\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e);\n\n        \u003cspan class=\"pl-c\"\u003e// 创建生产者线程\u003c/span\u003e\n        \u003cspan class=\"pl-smi\"\u003eThread\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eproducer\u003c/span\u003e = \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eThread\u003c/span\u003e(() -\u0026gt; {\n            \u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e {\n                \u003cspan class=\"pl-k\"\u003efor\u003c/span\u003e (\u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e = \u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e; \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e \u0026lt;= \u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e; \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e++) {\n                    \u003cspan class=\"pl-c\"\u003e// 向队列中添加元素，如果队列已满则阻塞等待\u003c/span\u003e\n                    \u003cspan class=\"pl-s1\"\u003equeue\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eput\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e);\n                    \u003cspan class=\"pl-smi\"\u003eSystem\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eout\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eprintln\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"生产者添加元素：\"\u003c/span\u003e + \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e);\n                }\n            } \u003cspan class=\"pl-k\"\u003ecatch\u003c/span\u003e (\u003cspan class=\"pl-smi\"\u003eInterruptedException\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e) {\n                \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eprintStackTrace\u003c/span\u003e();\n            }\n\n        });\n\n        \u003cspan class=\"pl-smi\"\u003eCountDownLatch\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ecountDownLatch\u003c/span\u003e = \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eCountDownLatch\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e);\n\n        \u003cspan class=\"pl-c\"\u003e// 创建消费者线程\u003c/span\u003e\n        \u003cspan class=\"pl-smi\"\u003eThread\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003econsumer\u003c/span\u003e = \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eThread\u003c/span\u003e(() -\u0026gt; {\n            \u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e {\n                \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e = \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e;\n                \u003cspan class=\"pl-k\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e) {\n\n                    \u003cspan class=\"pl-c\"\u003e// 从队列中取出元素，如果队列为空则阻塞等待\u003c/span\u003e\n                    \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eelement\u003c/span\u003e = \u003cspan class=\"pl-s1\"\u003equeue\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003etake\u003c/span\u003e();\n                    \u003cspan class=\"pl-smi\"\u003eSystem\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eout\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eprintln\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"消费者取出元素：\"\u003c/span\u003e + \u003cspan class=\"pl-s1\"\u003eelement\u003c/span\u003e);\n                    ++\u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e;\n                    \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e == \u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e) {\n                        \u003cspan class=\"pl-k\"\u003ebreak\u003c/span\u003e;\n                    }\n                }\n\n                \u003cspan class=\"pl-s1\"\u003ecountDownLatch\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003ecountDown\u003c/span\u003e();\n            } \u003cspan class=\"pl-k\"\u003ecatch\u003c/span\u003e (\u003cspan class=\"pl-smi\"\u003eInterruptedException\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e) {\n                \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eprintStackTrace\u003c/span\u003e();\n            }\n\n        });\n\n        \u003cspan class=\"pl-c\"\u003e// 启动线程\u003c/span\u003e\n        \u003cspan class=\"pl-s1\"\u003eproducer\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003estart\u003c/span\u003e();\n        \u003cspan class=\"pl-s1\"\u003econsumer\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003estart\u003c/span\u003e();\n\n        \u003cspan class=\"pl-c\"\u003e// 等待线程结束\u003c/span\u003e\n        \u003cspan class=\"pl-s1\"\u003eproducer\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003ejoin\u003c/span\u003e();\n        \u003cspan class=\"pl-s1\"\u003econsumer\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003ejoin\u003c/span\u003e();\n\n        \u003cspan class=\"pl-s1\"\u003ecountDownLatch\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eawait\u003c/span\u003e();\n\n        \u003cspan class=\"pl-s1\"\u003eproducer\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003einterrupt\u003c/span\u003e();\n        \u003cspan class=\"pl-s1\"\u003econsumer\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003einterrupt\u003c/span\u003e();\n    }\n\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e代码输出结果如下，可以看到只有生产者往队列中投放元素之后消费者才能消费，这也就意味着当队列中没有数据的时消费者就会阻塞，等待队列非空再继续消费。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c++ notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"生产者添加元素：1\n生产者添加元素：2\n消费者取出元素：1\n消费者取出元素：2\n消费者取出元素：3\n生产者添加元素：3\n生产者添加元素：4\n生产者添加元素：5\n消费者取出元素：4\n生产者添加元素：6\n消费者取出元素：5\n生产者添加元素：7\n生产者添加元素：8\n生产者添加元素：9\n生产者添加元素：10\n消费者取出元素：6\n消费者取出元素：7\n消费者取出元素：8\n消费者取出元素：9\n消费者取出元素：10\"\u003e\u003cpre\u003e生产者添加元素：\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\n生产者添加元素：\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\n消费者取出元素：\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e\n消费者取出元素：\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e\n消费者取出元素：\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\n生产者添加元素：\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e\n生产者添加元素：\u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e\n生产者添加元素：\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e\n消费者取出元素：\u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e\n生产者添加元素：\u003cspan class=\"pl-c1\"\u003e6\u003c/span\u003e\n消费者取出元素：\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e\n生产者添加元素：\u003cspan class=\"pl-c1\"\u003e7\u003c/span\u003e\n生产者添加元素：\u003cspan class=\"pl-c1\"\u003e8\u003c/span\u003e\n生产者添加元素：\u003cspan class=\"pl-c1\"\u003e9\u003c/span\u003e\n生产者添加元素：\u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e\n消费者取出元素：\u003cspan class=\"pl-c1\"\u003e6\u003c/span\u003e\n消费者取出元素：\u003cspan class=\"pl-c1\"\u003e7\u003c/span\u003e\n消费者取出元素：\u003cspan class=\"pl-c1\"\u003e8\u003c/span\u003e\n消费者取出元素：\u003cspan class=\"pl-c1\"\u003e9\u003c/span\u003e\n消费者取出元素：\u003cspan class=\"pl-c1\"\u003e10\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e了解了 \u003ccode\u003eput\u003c/code\u003e、\u003ccode\u003etake\u003c/code\u003e 这两个会阻塞的存和取方法之后，我我们再来看看阻塞队列中非阻塞的入队和出队方法 \u003ccode\u003eoffer\u003c/code\u003e 和 \u003ccode\u003epoll\u003c/code\u003e。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e如下所示，我们设置了一个大小为 3 的阻塞队列，我们会尝试在队列用 offer 方法存放 4 个元素，然后再从队列中用 \u003ccode\u003epoll\u003c/code\u003e 尝试取 4 次。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c++ notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public class OfferPollExample {\n\n    public static void main(String[] args) {\n        // 创建一个大小为 3 的 ArrayBlockingQueue\n        ArrayBlockingQueue\u0026lt;String\u0026gt; queue = new ArrayBlockingQueue\u0026lt;\u0026gt;(3);\n\n        // 向队列中添加元素\n        System.out.println(queue.offer(\u0026quot;A\u0026quot;));\n        System.out.println(queue.offer(\u0026quot;B\u0026quot;));\n        System.out.println(queue.offer(\u0026quot;C\u0026quot;));\n\n        // 尝试向队列中添加元素，但队列已满，返回 false\n        System.out.println(queue.offer(\u0026quot;D\u0026quot;));\n\n        // 从队列中取出元素\n        System.out.println(queue.poll());\n        System.out.println(queue.poll());\n        System.out.println(queue.poll());\n\n        // 尝试从队列中取出元素，但队列已空，返回 null\n        System.out.println(queue.poll());\n    }\n\n}\"\u003e\u003cpre\u003epublic \u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eOfferPollExample\u003c/span\u003e {\n\n    public \u003cspan class=\"pl-k\"\u003estatic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003evoid\u003c/span\u003e \u003cspan class=\"pl-en\"\u003emain\u003c/span\u003e(String[] args) {\n        \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e 创建一个大小为 3 的 ArrayBlockingQueue\u003c/span\u003e\n        ArrayBlockingQueue\u0026lt;String\u0026gt; queue = \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e ArrayBlockingQueue\u0026lt;\u0026gt;(\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e);\n\n        \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e 向队列中添加元素\u003c/span\u003e\n        System.\u003cspan class=\"pl-smi\"\u003eout\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003eprintln\u003c/span\u003e(queue.\u003cspan class=\"pl-c1\"\u003eoffer\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eA\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\n        System.\u003cspan class=\"pl-smi\"\u003eout\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003eprintln\u003c/span\u003e(queue.\u003cspan class=\"pl-c1\"\u003eoffer\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eB\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\n        System.\u003cspan class=\"pl-smi\"\u003eout\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003eprintln\u003c/span\u003e(queue.\u003cspan class=\"pl-c1\"\u003eoffer\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eC\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\n\n        \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e 尝试向队列中添加元素，但队列已满，返回 false\u003c/span\u003e\n        System.\u003cspan class=\"pl-smi\"\u003eout\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003eprintln\u003c/span\u003e(queue.\u003cspan class=\"pl-c1\"\u003eoffer\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eD\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e));\n\n        \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e 从队列中取出元素\u003c/span\u003e\n        System.\u003cspan class=\"pl-smi\"\u003eout\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003eprintln\u003c/span\u003e(queue.\u003cspan class=\"pl-c1\"\u003epoll\u003c/span\u003e());\n        System.\u003cspan class=\"pl-smi\"\u003eout\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003eprintln\u003c/span\u003e(queue.\u003cspan class=\"pl-c1\"\u003epoll\u003c/span\u003e());\n        System.\u003cspan class=\"pl-smi\"\u003eout\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003eprintln\u003c/span\u003e(queue.\u003cspan class=\"pl-c1\"\u003epoll\u003c/span\u003e());\n\n        \u003cspan class=\"pl-c\"\u003e\u003cspan class=\"pl-c\"\u003e//\u003c/span\u003e 尝试从队列中取出元素，但队列已空，返回 null\u003c/span\u003e\n        System.\u003cspan class=\"pl-smi\"\u003eout\u003c/span\u003e.\u003cspan class=\"pl-c1\"\u003eprintln\u003c/span\u003e(queue.\u003cspan class=\"pl-c1\"\u003epoll\u003c/span\u003e());\n    }\n\n}\u003cspan class=\"pl-ii\"\u003e\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e最终代码的输出结果如下，可以看到因为队列的大小为 3 的缘故，我们前 3 次存放到队列的结果为 true，第 4 次存放时，由于队列已满，所以存放结果返回 false。这也是为什么我们后续的 \u003ccode\u003epoll\u003c/code\u003e 方法只得到了 3 个元素的值。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c++ notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"true\ntrue\ntrue\nfalse\nA\nB\nC\nnull\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003efalse\u003c/span\u003e\nA\nB\nC\nnull\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e了解了阻塞存取和非阻塞存取，我们再来看看阻塞队列的一个比较特殊的操作，某些场景下，我们希望能够一次性将阻塞队列的结果存到列表中再进行批量操作，我们就可以使用阻塞队列的 \u003ccode\u003edrainTo\u003c/code\u003e 方法，这个方法会一次性将队列中所有元素存放到列表，如果队列中有元素，且成功存到 list 中则 \u003ccode\u003edrainTo\u003c/code\u003e 会返回本次转移到 list 中的元素数，反之若队列为空，\u003ccode\u003edrainTo\u003c/code\u003e 则直接返回 0。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public class DrainToExample {\n\n    public static void main(String[] args) {\n        // 创建一个大小为 5 的 ArrayBlockingQueue\n        ArrayBlockingQueue\u0026lt;Integer\u0026gt; queue = new ArrayBlockingQueue\u0026lt;\u0026gt;(5);\n\n        // 向队列中添加元素\n        queue.add(1);\n        queue.add(2);\n        queue.add(3);\n        queue.add(4);\n        queue.add(5);\n\n        // 创建一个 List，用于存储从队列中取出的元素\n        List\u0026lt;Integer\u0026gt; list = new ArrayList\u0026lt;\u0026gt;();\n\n        // 从队列中取出所有元素，并添加到 List 中\n        queue.drainTo(list);\n\n        // 输出 List 中的元素\n        System.out.println(list);\n    }\n\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eDrainToExample\u003c/span\u003e {\n\n    \u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003estatic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e \u003cspan class=\"pl-en\"\u003emain\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eString\u003c/span\u003e[] \u003cspan class=\"pl-s1\"\u003eargs\u003c/span\u003e) {\n        \u003cspan class=\"pl-c\"\u003e// 创建一个大小为 5 的 ArrayBlockingQueue\u003c/span\u003e\n        \u003cspan class=\"pl-smi\"\u003eArrayBlockingQueue\u003c/span\u003e\u0026lt;\u003cspan class=\"pl-smi\"\u003eInteger\u003c/span\u003e\u0026gt; \u003cspan class=\"pl-s1\"\u003equeue\u003c/span\u003e = \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eArrayBlockingQueue\u003c/span\u003e\u0026lt;\u0026gt;(\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e);\n\n        \u003cspan class=\"pl-c\"\u003e// 向队列中添加元素\u003c/span\u003e\n        \u003cspan class=\"pl-s1\"\u003equeue\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e);\n        \u003cspan class=\"pl-s1\"\u003equeue\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e);\n        \u003cspan class=\"pl-s1\"\u003equeue\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e);\n        \u003cspan class=\"pl-s1\"\u003equeue\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e);\n        \u003cspan class=\"pl-s1\"\u003equeue\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e(\u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e);\n\n        \u003cspan class=\"pl-c\"\u003e// 创建一个 List，用于存储从队列中取出的元素\u003c/span\u003e\n        \u003cspan class=\"pl-smi\"\u003eList\u003c/span\u003e\u0026lt;\u003cspan class=\"pl-smi\"\u003eInteger\u003c/span\u003e\u0026gt; \u003cspan class=\"pl-s1\"\u003elist\u003c/span\u003e = \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eArrayList\u003c/span\u003e\u0026lt;\u0026gt;();\n\n        \u003cspan class=\"pl-c\"\u003e// 从队列中取出所有元素，并添加到 List 中\u003c/span\u003e\n        \u003cspan class=\"pl-s1\"\u003equeue\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003edrainTo\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003elist\u003c/span\u003e);\n\n        \u003cspan class=\"pl-c\"\u003e// 输出 List 中的元素\u003c/span\u003e\n        \u003cspan class=\"pl-smi\"\u003eSystem\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eout\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eprintln\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003elist\u003c/span\u003e);\n    }\n\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e代码输出结果如下\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-c++ notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"[1, 2, 3, 4, 5]\"\u003e\u003cpre\u003e[\u003cspan class=\"pl-c1\"\u003e1\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e2\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e3\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e4\u003c/span\u003e, \u003cspan class=\"pl-c1\"\u003e5\u003c/span\u003e]\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eArrayBlockingQueue 源码分析\u003c/h2\u003e\u003ca id=\"user-content-arrayblockingqueue-源码分析\" class=\"anchor\" aria-label=\"Permalink: ArrayBlockingQueue 源码分析\" href=\"#arrayblockingqueue-源码分析\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e自此我们对阻塞队列的使用有了基本的印象，接下来我们就可以进一步了解一下 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 的工作机制了。\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e整体设计\u003c/h3\u003e\u003ca id=\"user-content-整体设计\" class=\"anchor\" aria-label=\"Permalink: 整体设计\" href=\"#整体设计\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e在了解 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 的具体细节之前，我们先来看看 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 的类图。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https://camo.githubusercontent.com/9bfb751edde6977973be217cd7e3da2282848fb22f0c38830e5a6f2296296cf8/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f6172726179626c6f636b696e6771756575652d636c6173732d6469616772616d2e706e67\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/9bfb751edde6977973be217cd7e3da2282848fb22f0c38830e5a6f2296296cf8/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f6172726179626c6f636b696e6771756575652d636c6173732d6469616772616d2e706e67\" alt=\"ArrayBlockingQueue 类图\" data-canonical-src=\"https://oss.javaguide.cn/github/javaguide/java/collection/arrayblockingqueue-class-diagram.png\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e从图中我们可以看出，\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 继承了阻塞队列 \u003ccode\u003eBlockingQueue\u003c/code\u003e 这个接口，不难猜出通过继承 \u003ccode\u003eBlockingQueue\u003c/code\u003e 这个接口之后，\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 就拥有了阻塞队列那些常见的操作行为。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e同时， \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 还继承了 \u003ccode\u003eAbstractQueue\u003c/code\u003e 这个抽象类，这个继承了 \u003ccode\u003eAbstractCollection\u003c/code\u003e 和 \u003ccode\u003eQueue\u003c/code\u003e 的抽象类，从抽象类的特定和语义我们也可以猜出，这个继承关系使得 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 拥有了队列的常见操作。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e所以我们是否可以得出这样一个结论，通过继承 \u003ccode\u003eAbstractQueue\u003c/code\u003e 获得队列所有的操作模板，其实现的入队和出队操作的整体框架。然后 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 通过继承 \u003ccode\u003eBlockingQueue\u003c/code\u003e 获取到阻塞队列的常见操作并将这些操作实现，填充到 \u003ccode\u003eAbstractQueue\u003c/code\u003e 模板方法的细节中，由此 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 成为一个完整的阻塞队列。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e为了印证这一点，我们到源码中一探究竟。首先我们先来看看 \u003ccode\u003eAbstractQueue\u003c/code\u003e，从类的继承关系我们可以大致得出，它通过 \u003ccode\u003eAbstractCollection\u003c/code\u003e 获得了集合的常见操作方法，然后通过 \u003ccode\u003eQueue\u003c/code\u003e 接口获得了队列的特性。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public abstract class AbstractQueue\u0026lt;E\u0026gt;\n    extends AbstractCollection\u0026lt;E\u0026gt;\n    implements Queue\u0026lt;E\u0026gt; {\n       //...\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eabstract\u003c/span\u003e \u003cspan class=\"pl-k\"\u003eclass\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eAbstractQueue\u003c/span\u003e\u0026lt;\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e\u0026gt;\n    \u003cspan class=\"pl-k\"\u003eextends\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eAbstractCollection\u003c/span\u003e\u0026lt;\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e\u0026gt;\n    \u003cspan class=\"pl-k\"\u003eimplements\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eQueue\u003c/span\u003e\u0026lt;\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e\u0026gt; {\n       \u003cspan class=\"pl-c\"\u003e//...\u003c/span\u003e\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e对于集合的操作无非是增删改查，所以我们不妨从添加方法入手，从源码中我们可以看到，它实现了 \u003ccode\u003eAbstractCollection\u003c/code\u003e 的 \u003ccode\u003eadd\u003c/code\u003e 方法，其内部逻辑如下:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e调用继承 \u003ccode\u003eQueue\u003c/code\u003e 接口的来的 \u003ccode\u003eoffer\u003c/code\u003e 方法，如果 \u003ccode\u003eoffer\u003c/code\u003e 成功则返回 \u003ccode\u003etrue\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e如果 \u003ccode\u003eoffer\u003c/code\u003e 失败，即代表当前元素入队失败直接抛异常。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public boolean add(E e) {\n  if (offer(e))\n      return true;\n  else\n      throw new IllegalStateException(\u0026quot;Queue full\u0026quot;);\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e) {\n  \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-en\"\u003eoffer\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e))\n      \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e;\n  \u003cspan class=\"pl-k\"\u003eelse\u003c/span\u003e\n      \u003cspan class=\"pl-k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eIllegalStateException\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"Queue full\"\u003c/span\u003e);\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e而 \u003ccode\u003eAbstractQueue\u003c/code\u003e 中并没有对 \u003ccode\u003eQueue\u003c/code\u003e 的 \u003ccode\u003eoffer\u003c/code\u003e 的实现，很明显这样做的目的是定义好了 \u003ccode\u003eadd\u003c/code\u003e 的核心逻辑，将 \u003ccode\u003eoffer\u003c/code\u003e 的细节交由其子类即我们的 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 实现。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e到此，我们对于抽象类 \u003ccode\u003eAbstractQueue\u003c/code\u003e 的分析就结束了，我们继续看看 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 中另一个重要的继承接口 \u003ccode\u003eBlockingQueue\u003c/code\u003e。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e点开 \u003ccode\u003eBlockingQueue\u003c/code\u003e 之后，我们可以看到这个接口同样继承了 \u003ccode\u003eQueue\u003c/code\u003e 接口，这就意味着它也具备了队列所拥有的所有行为。同时，它还定义了自己所需要实现的方法。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public interface BlockingQueue\u0026lt;E\u0026gt; extends Queue\u0026lt;E\u0026gt; {\n\n     //元素入队成功返回true，反之则会抛出异常IllegalStateException\n    boolean add(E e);\n\n     //元素入队成功返回true，反之返回false\n    boolean offer(E e);\n\n     //元素入队成功则直接返回，如果队列已满元素不可入队则将线程阻塞，因为阻塞期间可能会被打断，所以这里方法签名抛出了InterruptedException\n    void put(E e) throws InterruptedException;\n\n   //和上一个方法一样,只不过队列满时只会阻塞单位为unit，时间为timeout的时长，如果在等待时长内没有入队成功则直接返回false。\n    boolean offer(E e, long timeout, TimeUnit unit)\n        throws InterruptedException;\n\n    //从队头取出一个元素，如果队列为空则阻塞等待，因为会阻塞线程的缘故，所以该方法可能会被打断，所以签名定义了InterruptedException\n    E take() throws InterruptedException;\n\n      //取出队头的元素并返回，如果当前队列为空则阻塞等待timeout且单位为unit的时长，如果这个时间段没有元素则直接返回null。\n    E poll(long timeout, TimeUnit unit)\n        throws InterruptedException;\n\n      //获取队列剩余元素个数\n    int remainingCapacity();\n\n     //删除我们指定的对象，如果成功返回true，反之返回false。\n    boolean remove(Object o);\n\n    //判断队列中是否包含指定元素\n    public boolean contains(Object o);\n\n     //将队列中的元素全部存到指定的集合中\n    int drainTo(Collection\u0026lt;? super E\u0026gt; c);\n\n    //转移maxElements个元素到集合中\n    int drainTo(Collection\u0026lt;? super E\u0026gt; c, int maxElements);\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-k\"\u003einterface\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eBlockingQueue\u003c/span\u003e\u0026lt;\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e\u0026gt; \u003cspan class=\"pl-k\"\u003eextends\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eQueue\u003c/span\u003e\u0026lt;\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e\u0026gt; {\n\n     \u003cspan class=\"pl-c\"\u003e//元素入队成功返回true，反之则会抛出异常IllegalStateException\u003c/span\u003e\n    \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e);\n\n     \u003cspan class=\"pl-c\"\u003e//元素入队成功返回true，反之返回false\u003c/span\u003e\n    \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eoffer\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e);\n\n     \u003cspan class=\"pl-c\"\u003e//元素入队成功则直接返回，如果队列已满元素不可入队则将线程阻塞，因为阻塞期间可能会被打断，所以这里方法签名抛出了InterruptedException\u003c/span\u003e\n    \u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eput\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e) \u003cspan class=\"pl-k\"\u003ethrows\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eInterruptedException\u003c/span\u003e;\n\n   \u003cspan class=\"pl-c\"\u003e//和上一个方法一样,只不过队列满时只会阻塞单位为unit，时间为timeout的时长，如果在等待时长内没有入队成功则直接返回false。\u003c/span\u003e\n    \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eoffer\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e, \u003cspan class=\"pl-smi\"\u003elong\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003etimeout\u003c/span\u003e, \u003cspan class=\"pl-smi\"\u003eTimeUnit\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eunit\u003c/span\u003e)\n        \u003cspan class=\"pl-k\"\u003ethrows\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eInterruptedException\u003c/span\u003e;\n\n    \u003cspan class=\"pl-c\"\u003e//从队头取出一个元素，如果队列为空则阻塞等待，因为会阻塞线程的缘故，所以该方法可能会被打断，所以签名定义了InterruptedException\u003c/span\u003e\n    \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-en\"\u003etake\u003c/span\u003e() \u003cspan class=\"pl-k\"\u003ethrows\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eInterruptedException\u003c/span\u003e;\n\n      \u003cspan class=\"pl-c\"\u003e//取出队头的元素并返回，如果当前队列为空则阻塞等待timeout且单位为unit的时长，如果这个时间段没有元素则直接返回null。\u003c/span\u003e\n    \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-en\"\u003epoll\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003elong\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003etimeout\u003c/span\u003e, \u003cspan class=\"pl-smi\"\u003eTimeUnit\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eunit\u003c/span\u003e)\n        \u003cspan class=\"pl-k\"\u003ethrows\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eInterruptedException\u003c/span\u003e;\n\n      \u003cspan class=\"pl-c\"\u003e//获取队列剩余元素个数\u003c/span\u003e\n    \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eremainingCapacity\u003c/span\u003e();\n\n     \u003cspan class=\"pl-c\"\u003e//删除我们指定的对象，如果成功返回true，反之返回false。\u003c/span\u003e\n    \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eremove\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eObject\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eo\u003c/span\u003e);\n\n    \u003cspan class=\"pl-c\"\u003e//判断队列中是否包含指定元素\u003c/span\u003e\n    \u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-en\"\u003econtains\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eObject\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eo\u003c/span\u003e);\n\n     \u003cspan class=\"pl-c\"\u003e//将队列中的元素全部存到指定的集合中\u003c/span\u003e\n    \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-en\"\u003edrainTo\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eCollection\u003c/span\u003e\u0026lt;? \u003cspan class=\"pl-en\"\u003esuper\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e\u0026gt; \u003cspan class=\"pl-s1\"\u003ec\u003c/span\u003e);\n\n    \u003cspan class=\"pl-c\"\u003e//转移maxElements个元素到集合中\u003c/span\u003e\n    \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-en\"\u003edrainTo\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eCollection\u003c/span\u003e\u0026lt;? \u003cspan class=\"pl-en\"\u003esuper\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e\u0026gt; \u003cspan class=\"pl-s1\"\u003ec\u003c/span\u003e, \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003emaxElements\u003c/span\u003e);\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e了解了 \u003ccode\u003eBlockingQueue\u003c/code\u003e 的常见操作后，我们就知道了 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 通过继承 \u003ccode\u003eBlockingQueue\u003c/code\u003e 的方法并实现后，填充到 \u003ccode\u003eAbstractQueue\u003c/code\u003e 的方法上，由此我们便知道了上文中 \u003ccode\u003eAbstractQueue\u003c/code\u003e 的 \u003ccode\u003eadd\u003c/code\u003e 方法的 \u003ccode\u003eoffer\u003c/code\u003e 方法是哪里是实现的了。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public boolean add(E e) {\n  //AbstractQueue的offer来自下层的ArrayBlockingQueue从BlockingQueue继承并实现的offer方法\n  if (offer(e))\n      return true;\n  else\n      throw new IllegalStateException(\u0026quot;Queue full\u0026quot;);\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e) {\n  \u003cspan class=\"pl-c\"\u003e//AbstractQueue的offer来自下层的ArrayBlockingQueue从BlockingQueue继承并实现的offer方法\u003c/span\u003e\n  \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-en\"\u003eoffer\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e))\n      \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e;\n  \u003cspan class=\"pl-k\"\u003eelse\u003c/span\u003e\n      \u003cspan class=\"pl-k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eIllegalStateException\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"Queue full\"\u003c/span\u003e);\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e初始化\u003c/h3\u003e\u003ca id=\"user-content-初始化\" class=\"anchor\" aria-label=\"Permalink: 初始化\" href=\"#初始化\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e了解 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 的细节前，我们不妨先看看其构造函数，了解一下其初始化过程。从源码中我们可以看出 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 有 3 个构造方法，而最核心的构造方法就是下方这一个。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"// capacity 表示队列初始容量，fair 表示 锁的公平性\npublic ArrayBlockingQueue(int capacity, boolean fair) {\n  //如果设置的队列大小小于0，则直接抛出IllegalArgumentException\n  if (capacity \u0026lt;= 0)\n      throw new IllegalArgumentException();\n  //初始化一个数组用于存放队列的元素\n  this.items = new Object[capacity];\n  //创建阻塞队列流程控制的锁\n  lock = new ReentrantLock(fair);\n  //用lock锁创建两个条件控制队列生产和消费\n  notEmpty = lock.newCondition();\n  notFull =  lock.newCondition();\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-c\"\u003e// capacity 表示队列初始容量，fair 表示 锁的公平性\u003c/span\u003e\n\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eArrayBlockingQueue\u003c/span\u003e\u003cspan class=\"pl-en\"\u003e\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ecapacity\u003c/span\u003e, \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003efair\u003c/span\u003e) {\n  \u003cspan class=\"pl-c\"\u003e//如果设置的队列大小小于0，则直接抛出IllegalArgumentException\u003c/span\u003e\n  \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecapacity\u003c/span\u003e \u0026lt;= \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e)\n      \u003cspan class=\"pl-k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eIllegalArgumentException\u003c/span\u003e();\n  \u003cspan class=\"pl-c\"\u003e//初始化一个数组用于存放队列的元素\u003c/span\u003e\n  \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e = \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eObject\u003c/span\u003e[\u003cspan class=\"pl-s1\"\u003ecapacity\u003c/span\u003e];\n  \u003cspan class=\"pl-c\"\u003e//创建阻塞队列流程控制的锁\u003c/span\u003e\n  \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e = \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eReentrantLock\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003efair\u003c/span\u003e);\n  \u003cspan class=\"pl-c\"\u003e//用lock锁创建两个条件控制队列生产和消费\u003c/span\u003e\n  \u003cspan class=\"pl-s1\"\u003enotEmpty\u003c/span\u003e = \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003enewCondition\u003c/span\u003e();\n  \u003cspan class=\"pl-s1\"\u003enotFull\u003c/span\u003e =  \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003enewCondition\u003c/span\u003e();\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e这个构造方法里面有两个比较核心的成员变量 \u003ccode\u003enotEmpty\u003c/code\u003e(非空) 和 \u003ccode\u003enotFull\u003c/code\u003e （非满） ，需要我们格外留意，它们是实现生产者和消费者有序工作的关键所在，这一点笔者会在后续的源码解析中详细说明，这里我们只需初步了解一下阻塞队列的构造即可。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e另外两个构造方法都是基于上述的构造方法，默认情况下，我们会使用下面这个构造方法，该构造方法就意味着 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 用的是非公平锁，即各个生产者或者消费者线程收到通知后，对于锁的争抢是随机的。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\" public ArrayBlockingQueue(int capacity) {\n        this(capacity, false);\n    }\"\u003e\u003cpre\u003e \u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eArrayBlockingQueue\u003c/span\u003e\u003cspan class=\"pl-en\"\u003e\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ecapacity\u003c/span\u003e) {\n        \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ecapacity\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003efalse\u003c/span\u003e);\n    }\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e还有一个不怎么常用的构造方法，在初始化容量和锁的非公平性之后，它还提供了一个 \u003ccode\u003eCollection\u003c/code\u003e 参数，从源码中不难看出这个构造方法是将外部传入的集合的元素在初始化时直接存放到阻塞队列中。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public ArrayBlockingQueue(int capacity, boolean fair,\n                              Collection\u0026lt;? extends E\u0026gt; c) {\n  //初始化容量和锁的公平性\n  this(capacity, fair);\n\n  final ReentrantLock lock = this.lock;\n  //上锁并将c中的元素存放到ArrayBlockingQueue底层的数组中\n  lock.lock();\n  try {\n      int i = 0;\n      try {\n                //遍历并添加元素到数组中\n          for (E e : c) {\n              checkNotNull(e);\n              items[i++] = e;\n          }\n      } catch (ArrayIndexOutOfBoundsException ex) {\n          throw new IllegalArgumentException();\n      }\n      //记录当前队列容量\n      count = i;\n                      //更新下一次put或者offer或用add方法添加到队列底层数组的位置\n      putIndex = (i == capacity) ? 0 : i;\n  } finally {\n      //完成遍历后释放锁\n      lock.unlock();\n  }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eArrayBlockingQueue\u003c/span\u003e\u003cspan class=\"pl-en\"\u003e\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ecapacity\u003c/span\u003e, \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003efair\u003c/span\u003e,\n                              \u003cspan class=\"pl-smi\"\u003eCollection\u003c/span\u003e\u0026lt;? \u003cspan class=\"pl-k\"\u003eextends\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e\u0026gt; \u003cspan class=\"pl-s1\"\u003ec\u003c/span\u003e) {\n  \u003cspan class=\"pl-c\"\u003e//初始化容量和锁的公平性\u003c/span\u003e\n  \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ecapacity\u003c/span\u003e, \u003cspan class=\"pl-s1\"\u003efair\u003c/span\u003e);\n\n  \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eReentrantLock\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e;\n  \u003cspan class=\"pl-c\"\u003e//上锁并将c中的元素存放到ArrayBlockingQueue底层的数组中\u003c/span\u003e\n  \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003elock\u003c/span\u003e();\n  \u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e {\n      \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e = \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e;\n      \u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e {\n                \u003cspan class=\"pl-c\"\u003e//遍历并添加元素到数组中\u003c/span\u003e\n          \u003cspan class=\"pl-k\"\u003efor\u003c/span\u003e (\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e : \u003cspan class=\"pl-s1\"\u003ec\u003c/span\u003e) {\n              \u003cspan class=\"pl-en\"\u003echeckNotNull\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e);\n              \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e[\u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e++] = \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e;\n          }\n      } \u003cspan class=\"pl-k\"\u003ecatch\u003c/span\u003e (\u003cspan class=\"pl-smi\"\u003eArrayIndexOutOfBoundsException\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eex\u003c/span\u003e) {\n          \u003cspan class=\"pl-k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eIllegalArgumentException\u003c/span\u003e();\n      }\n      \u003cspan class=\"pl-c\"\u003e//记录当前队列容量\u003c/span\u003e\n      \u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e = \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e;\n                      \u003cspan class=\"pl-c\"\u003e//更新下一次put或者offer或用add方法添加到队列底层数组的位置\u003c/span\u003e\n      \u003cspan class=\"pl-s1\"\u003eputIndex\u003c/span\u003e = (\u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e == \u003cspan class=\"pl-s1\"\u003ecapacity\u003c/span\u003e) ? \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e : \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e;\n  } \u003cspan class=\"pl-k\"\u003efinally\u003c/span\u003e {\n      \u003cspan class=\"pl-c\"\u003e//完成遍历后释放锁\u003c/span\u003e\n      \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eunlock\u003c/span\u003e();\n  }\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e阻塞式获取和新增元素\u003c/h3\u003e\u003ca id=\"user-content-阻塞式获取和新增元素\" class=\"anchor\" aria-label=\"Permalink: 阻塞式获取和新增元素\" href=\"#阻塞式获取和新增元素\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 阻塞式获取和新增元素对应的就是生产者-消费者模型，虽然它也支持非阻塞式获取和新增元素（例如 \u003ccode\u003epoll()\u003c/code\u003e 和 \u003ccode\u003eoffer(E e)\u003c/code\u003e 方法，后文会介绍到），但一般不会使用。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 阻塞式获取和新增元素的方法为：\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eput(E e)\u003c/code\u003e：将元素插入队列中，如果队列已满，则该方法会一直阻塞，直到队列有空间可用或者线程被中断。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003etake()\u003c/code\u003e ：获取并移除队列头部的元素，如果队列为空，则该方法会一直阻塞，直到队列非空或者线程被中断。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e这两个方法实现的关键就是在于两个条件对象 \u003ccode\u003enotEmpty\u003c/code\u003e(非空) 和 \u003ccode\u003enotFull\u003c/code\u003e （非满），这个我们在上文的构造方法中有提到。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e接下来笔者就通过两张图让大家了解一下这两个条件是如何在阻塞队列中运用的。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https://camo.githubusercontent.com/d9874a7286006d63b247b9bc7c24521c8ff1bff07c80d07b0a6d812ff0a4da7e/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6e6f74456d7074792d74616b652e706e67\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/d9874a7286006d63b247b9bc7c24521c8ff1bff07c80d07b0a6d812ff0a4da7e/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6e6f74456d7074792d74616b652e706e67\" alt=\"ArrayBlockingQueue 非空条件\" data-canonical-src=\"https://oss.javaguide.cn/github/javaguide/java/collection/ArrayBlockingQueue-notEmpty-take.png\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e假设我们的代码消费者先启动，当它发现队列中没有数据，那么非空条件就会将这个线程挂起，即等待条件非空时挂起。然后 CPU 执行权到达生产者，生产者发现队列中可以存放数据，于是将数据存放进去，通知此时条件非空，此时消费者就会被唤醒到队列中使用 \u003ccode\u003etake\u003c/code\u003e 等方法获取值了。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https://camo.githubusercontent.com/5c766e4ce2e633117eb919e921e12a54c4cf128c27bd4c3bdb10c84072ab1c81/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6e6f7446756c6c2d7075742e706e67\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/5c766e4ce2e633117eb919e921e12a54c4cf128c27bd4c3bdb10c84072ab1c81/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6e6f7446756c6c2d7075742e706e67\" alt=\"ArrayBlockingQueue 非满条件\" data-canonical-src=\"https://oss.javaguide.cn/github/javaguide/java/collection/ArrayBlockingQueue-notFull-put.png\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e随后的执行中，生产者生产速度远远大于消费者消费速度，于是生产者将队列塞满后再次尝试将数据存入队列，发现队列已满，于是阻塞队列就将当前线程挂起，等待非满。然后消费者拿着 CPU 执行权进行消费，于是队列可以存放新数据了，发出一个非满的通知，此时挂起的生产者就会等待 CPU 执行权到来时再次尝试将数据存到队列中。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e简单了解阻塞队列的基于两个条件的交互流程之后，我们不妨看看 \u003ccode\u003eput\u003c/code\u003e 和 \u003ccode\u003etake\u003c/code\u003e 方法的源码。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public void put(E e) throws InterruptedException {\n    //确保插入的元素不为null\n    checkNotNull(e);\n    //加锁\n    final ReentrantLock lock = this.lock;\n    //这里使用lockInterruptibly()方法而不是lock()方法是为了能够响应中断操作，如果在等待获取锁的过程中被打断则该方法会抛出InterruptedException异常。\n    lock.lockInterruptibly();\n    try {\n            //如果count等数组长度则说明队列已满，当前线程将被挂起放到AQS队列中，等待队列非满时插入（非满条件）。\n       //在等待期间，锁会被释放，其他线程可以继续对队列进行操作。\n        while (count == items.length)\n            notFull.await();\n           //如果队列可以存放元素，则调用enqueue将元素入队\n        enqueue(e);\n    } finally {\n        //释放锁\n        lock.unlock();\n    }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eput\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e) \u003cspan class=\"pl-k\"\u003ethrows\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eInterruptedException\u003c/span\u003e {\n    \u003cspan class=\"pl-c\"\u003e//确保插入的元素不为null\u003c/span\u003e\n    \u003cspan class=\"pl-en\"\u003echeckNotNull\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e);\n    \u003cspan class=\"pl-c\"\u003e//加锁\u003c/span\u003e\n    \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eReentrantLock\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e;\n    \u003cspan class=\"pl-c\"\u003e//这里使用lockInterruptibly()方法而不是lock()方法是为了能够响应中断操作，如果在等待获取锁的过程中被打断则该方法会抛出InterruptedException异常。\u003c/span\u003e\n    \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003elockInterruptibly\u003c/span\u003e();\n    \u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e {\n            \u003cspan class=\"pl-c\"\u003e//如果count等数组长度则说明队列已满，当前线程将被挂起放到AQS队列中，等待队列非满时插入（非满条件）。\u003c/span\u003e\n       \u003cspan class=\"pl-c\"\u003e//在等待期间，锁会被释放，其他线程可以继续对队列进行操作。\u003c/span\u003e\n        \u003cspan class=\"pl-k\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e == \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elength\u003c/span\u003e)\n            \u003cspan class=\"pl-s1\"\u003enotFull\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eawait\u003c/span\u003e();\n           \u003cspan class=\"pl-c\"\u003e//如果队列可以存放元素，则调用enqueue将元素入队\u003c/span\u003e\n        \u003cspan class=\"pl-en\"\u003eenqueue\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e);\n    } \u003cspan class=\"pl-k\"\u003efinally\u003c/span\u003e {\n        \u003cspan class=\"pl-c\"\u003e//释放锁\u003c/span\u003e\n        \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eunlock\u003c/span\u003e();\n    }\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eput\u003c/code\u003e方法内部调用了 \u003ccode\u003eenqueue\u003c/code\u003e 方法来实现元素入队，我们继续深入查看一下 \u003ccode\u003eenqueue\u003c/code\u003e 方法的实现细节：\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"private void enqueue(E x) {\n   //获取队列底层的数组\n    final Object[] items = this.items;\n    //将putindex位置的值设置为我们传入的x\n    items[putIndex] = x;\n    //更新putindex，如果putindex等于数组长度，则更新为0\n    if (++putIndex == items.length)\n        putIndex = 0;\n    //队列长度+1\n    count++;\n    //通知队列非空，那些因为获取元素而阻塞的线程可以继续工作了\n    notEmpty.signal();\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eprivate\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003evoid\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eenqueue\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ex\u003c/span\u003e) {\n   \u003cspan class=\"pl-c\"\u003e//获取队列底层的数组\u003c/span\u003e\n    \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eObject\u003c/span\u003e[] \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e;\n    \u003cspan class=\"pl-c\"\u003e//将putindex位置的值设置为我们传入的x\u003c/span\u003e\n    \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e[\u003cspan class=\"pl-s1\"\u003eputIndex\u003c/span\u003e] = \u003cspan class=\"pl-s1\"\u003ex\u003c/span\u003e;\n    \u003cspan class=\"pl-c\"\u003e//更新putindex，如果putindex等于数组长度，则更新为0\u003c/span\u003e\n    \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (++\u003cspan class=\"pl-s1\"\u003eputIndex\u003c/span\u003e == \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elength\u003c/span\u003e)\n        \u003cspan class=\"pl-s1\"\u003eputIndex\u003c/span\u003e = \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e;\n    \u003cspan class=\"pl-c\"\u003e//队列长度+1\u003c/span\u003e\n    \u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e++;\n    \u003cspan class=\"pl-c\"\u003e//通知队列非空，那些因为获取元素而阻塞的线程可以继续工作了\u003c/span\u003e\n    \u003cspan class=\"pl-s1\"\u003enotEmpty\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003esignal\u003c/span\u003e();\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e从源码中可以看到入队操作的逻辑就是在数组中追加一个新元素，整体执行步骤为:\u003c/p\u003e\n\u003col dir=\"auto\"\u003e\n\u003cli\u003e获取 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 底层的数组 \u003ccode\u003eitems\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e将元素存到 \u003ccode\u003eputIndex\u003c/code\u003e 位置。\u003c/li\u003e\n\u003cli\u003e更新 \u003ccode\u003eputIndex\u003c/code\u003e 到下一个位置，如果 \u003ccode\u003eputIndex\u003c/code\u003e 等于队列长度，则说明 \u003ccode\u003eputIndex\u003c/code\u003e 已经到达数组末尾了，下一次插入则需要 0 开始。(\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 用到了循环队列的思想，即从头到尾循环复用一个数组)\u003c/li\u003e\n\u003cli\u003e更新 \u003ccode\u003ecount\u003c/code\u003e 的值，表示当前队列长度+1。\u003c/li\u003e\n\u003cli\u003e调用 \u003ccode\u003enotEmpty.signal()\u003c/code\u003e 通知队列非空，消费者可以从队列中获取值了。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp dir=\"auto\"\u003e自此我们了解了 \u003ccode\u003eput\u003c/code\u003e 方法的流程，为了更加完整的了解 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 关于生产者-消费者模型的设计，我们继续看看阻塞获取队列元素的 \u003ccode\u003etake\u003c/code\u003e 方法。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public E take() throws InterruptedException {\n       //获取锁\n     final ReentrantLock lock = this.lock;\n     lock.lockInterruptibly();\n     try {\n             //如果队列中元素个数为0，则将当前线程打断并存入AQS队列中，等待队列非空时获取并移除元素（非空条件）\n         while (count == 0)\n             notEmpty.await();\n            //如果队列不为空则调用dequeue获取元素\n         return dequeue();\n     } finally {\n          //释放锁\n         lock.unlock();\n     }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-en\"\u003etake\u003c/span\u003e() \u003cspan class=\"pl-k\"\u003ethrows\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eInterruptedException\u003c/span\u003e {\n       \u003cspan class=\"pl-c\"\u003e//获取锁\u003c/span\u003e\n     \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eReentrantLock\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e;\n     \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003elockInterruptibly\u003c/span\u003e();\n     \u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e {\n             \u003cspan class=\"pl-c\"\u003e//如果队列中元素个数为0，则将当前线程打断并存入AQS队列中，等待队列非空时获取并移除元素（非空条件）\u003c/span\u003e\n         \u003cspan class=\"pl-k\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e == \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e)\n             \u003cspan class=\"pl-s1\"\u003enotEmpty\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eawait\u003c/span\u003e();\n            \u003cspan class=\"pl-c\"\u003e//如果队列不为空则调用dequeue获取元素\u003c/span\u003e\n         \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003edequeue\u003c/span\u003e();\n     } \u003cspan class=\"pl-k\"\u003efinally\u003c/span\u003e {\n          \u003cspan class=\"pl-c\"\u003e//释放锁\u003c/span\u003e\n         \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eunlock\u003c/span\u003e();\n     }\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e理解了 \u003ccode\u003eput\u003c/code\u003e 方法再看\u003ccode\u003etake\u003c/code\u003e 方法就很简单了，其核心逻辑和\u003ccode\u003eput\u003c/code\u003e 方法正好是相反的，比如\u003ccode\u003eput\u003c/code\u003e 方法在队列满的时候等待队列非满时插入元素（非满条件），而\u003ccode\u003etake\u003c/code\u003e 方法等待队列非空时获取并移除元素（非空条件）。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003etake\u003c/code\u003e方法内部调用了 \u003ccode\u003edequeue\u003c/code\u003e 方法来实现元素出队，其核心逻辑和 \u003ccode\u003eenqueue\u003c/code\u003e 方法也是相反的。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"private E dequeue() {\n  //获取阻塞队列底层的数组\n  final Object[] items = this.items;\n  @SuppressWarnings(\u0026quot;unchecked\u0026quot;)\n  //从队列中获取takeIndex位置的元素\n  E x = (E) items[takeIndex];\n  //将takeIndex置空\n  items[takeIndex] = null;\n  //takeIndex向后挪动，如果等于数组长度则更新为0\n  if (++takeIndex == items.length)\n      takeIndex = 0;\n  //队列长度减1\n  count--;\n  if (itrs != null)\n      itrs.elementDequeued();\n  //通知那些被打断的线程当前队列状态非满，可以继续存放元素\n  notFull.signal();\n  return x;\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003eprivate\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-en\"\u003edequeue\u003c/span\u003e() {\n  \u003cspan class=\"pl-c\"\u003e//获取阻塞队列底层的数组\u003c/span\u003e\n  \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eObject\u003c/span\u003e[] \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e;\n  \u003cspan class=\"pl-c1\"\u003e@\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003eSuppressWarnings\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"unchecked\"\u003c/span\u003e)\n  \u003cspan class=\"pl-c\"\u003e//从队列中获取takeIndex位置的元素\u003c/span\u003e\n  \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ex\u003c/span\u003e = (\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e) \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e[\u003cspan class=\"pl-s1\"\u003etakeIndex\u003c/span\u003e];\n  \u003cspan class=\"pl-c\"\u003e//将takeIndex置空\u003c/span\u003e\n  \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e[\u003cspan class=\"pl-s1\"\u003etakeIndex\u003c/span\u003e] = \u003cspan class=\"pl-c1\"\u003enull\u003c/span\u003e;\n  \u003cspan class=\"pl-c\"\u003e//takeIndex向后挪动，如果等于数组长度则更新为0\u003c/span\u003e\n  \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (++\u003cspan class=\"pl-s1\"\u003etakeIndex\u003c/span\u003e == \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elength\u003c/span\u003e)\n      \u003cspan class=\"pl-s1\"\u003etakeIndex\u003c/span\u003e = \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e;\n  \u003cspan class=\"pl-c\"\u003e//队列长度减1\u003c/span\u003e\n  \u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e--;\n  \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003eitrs\u003c/span\u003e != \u003cspan class=\"pl-c1\"\u003enull\u003c/span\u003e)\n      \u003cspan class=\"pl-s1\"\u003eitrs\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eelementDequeued\u003c/span\u003e();\n  \u003cspan class=\"pl-c\"\u003e//通知那些被打断的线程当前队列状态非满，可以继续存放元素\u003c/span\u003e\n  \u003cspan class=\"pl-s1\"\u003enotFull\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003esignal\u003c/span\u003e();\n  \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ex\u003c/span\u003e;\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e由于\u003ccode\u003edequeue\u003c/code\u003e 方法（出队）和上面介绍的 \u003ccode\u003eenqueue\u003c/code\u003e 方法（入队）的步骤大致类似，这里就不重复介绍了。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e为了帮助理解，我专门画了一张图来展示 \u003ccode\u003enotEmpty\u003c/code\u003e(非空) 和 \u003ccode\u003enotFull\u003c/code\u003e （非满）这两个条件对象是如何控制 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 的存和取的。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https://camo.githubusercontent.com/999005dccc8278ce18e7c2ade8b47cfbc4c5f2faac946c11aa3329617015ebb5/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6e6f74456d7074792d6e6f7446756c6c2e706e67\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/999005dccc8278ce18e7c2ade8b47cfbc4c5f2faac946c11aa3329617015ebb5/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6e6f74456d7074792d6e6f7446756c6c2e706e67\" alt=\"ArrayBlockingQueue 非空非满\" data-canonical-src=\"https://oss.javaguide.cn/github/javaguide/java/collection/ArrayBlockingQueue-notEmpty-notFull.png\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003cstrong\u003e消费者\u003c/strong\u003e：当消费者从队列中 \u003ccode\u003etake\u003c/code\u003e 或者 \u003ccode\u003epoll\u003c/code\u003e 等操作取出一个元素之后，就会通知队列非满，此时那些等待非满的生产者就会被唤醒等待获取 CPU 时间片进行入队操作。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e生产者\u003c/strong\u003e：当生产者将元素存到队列中后，就会触发通知队列非空，此时消费者就会被唤醒等待 CPU 时间片尝试获取元素。如此往复，两个条件对象就构成一个环路，控制着多线程之间的存和取。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e非阻塞式获取和新增元素\u003c/h3\u003e\u003ca id=\"user-content-非阻塞式获取和新增元素\" class=\"anchor\" aria-label=\"Permalink: 非阻塞式获取和新增元素\" href=\"#非阻塞式获取和新增元素\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 非阻塞式获取和新增元素的方法为：\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eoffer(E e)\u003c/code\u003e：将元素插入队列尾部。如果队列已满，则该方法会直接返回 false，不会等待并阻塞线程。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epoll()\u003c/code\u003e：获取并移除队列头部的元素，如果队列为空，则该方法会直接返回 null，不会等待并阻塞线程。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eadd(E e)\u003c/code\u003e：将元素插入队列尾部。如果队列已满则会抛出 \u003ccode\u003eIllegalStateException\u003c/code\u003e 异常，底层基于 \u003ccode\u003eoffer(E e)\u003c/code\u003e 方法。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eremove()\u003c/code\u003e：移除队列头部的元素，如果队列为空则会抛出 \u003ccode\u003eNoSuchElementException\u003c/code\u003e 异常，底层基于 \u003ccode\u003epoll()\u003c/code\u003e。\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003epeek()\u003c/code\u003e：获取但不移除队列头部的元素，如果队列为空，则该方法会直接返回 null，不会等待并阻塞线程。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e先来看看 \u003ccode\u003eoffer\u003c/code\u003e 方法，逻辑和 \u003ccode\u003eput\u003c/code\u003e 差不多，唯一的区别就是入队失败时不会阻塞当前线程，而是直接返回 \u003ccode\u003efalse\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public boolean offer(E e) {\n        //确保插入的元素不为null\n        checkNotNull(e);\n        //获取锁\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n             //队列已满直接返回false\n            if (count == items.length)\n                return false;\n            else {\n                //反之将元素入队并直接返回true\n                enqueue(e);\n                return true;\n            }\n        } finally {\n            //释放锁\n            lock.unlock();\n        }\n    }\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eoffer\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e) {\n        \u003cspan class=\"pl-c\"\u003e//确保插入的元素不为null\u003c/span\u003e\n        \u003cspan class=\"pl-en\"\u003echeckNotNull\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e);\n        \u003cspan class=\"pl-c\"\u003e//获取锁\u003c/span\u003e\n        \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eReentrantLock\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e;\n        \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003elock\u003c/span\u003e();\n        \u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e {\n             \u003cspan class=\"pl-c\"\u003e//队列已满直接返回false\u003c/span\u003e\n            \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e == \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elength\u003c/span\u003e)\n                \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003efalse\u003c/span\u003e;\n            \u003cspan class=\"pl-k\"\u003eelse\u003c/span\u003e {\n                \u003cspan class=\"pl-c\"\u003e//反之将元素入队并直接返回true\u003c/span\u003e\n                \u003cspan class=\"pl-en\"\u003eenqueue\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e);\n                \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e;\n            }\n        } \u003cspan class=\"pl-k\"\u003efinally\u003c/span\u003e {\n            \u003cspan class=\"pl-c\"\u003e//释放锁\u003c/span\u003e\n            \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eunlock\u003c/span\u003e();\n        }\n    }\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003epoll\u003c/code\u003e 方法同理，获取元素失败也是直接返回空，并不会阻塞获取元素的线程。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public E poll() {\n        final ReentrantLock lock = this.lock;\n        //上锁\n        lock.lock();\n        try {\n            //如果队列为空直接返回null，反之出队返回元素值\n            return (count == 0) ? null : dequeue();\n        } finally {\n            lock.unlock();\n        }\n    }\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-en\"\u003epoll\u003c/span\u003e() {\n        \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eReentrantLock\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e;\n        \u003cspan class=\"pl-c\"\u003e//上锁\u003c/span\u003e\n        \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003elock\u003c/span\u003e();\n        \u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e {\n            \u003cspan class=\"pl-c\"\u003e//如果队列为空直接返回null，反之出队返回元素值\u003c/span\u003e\n            \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e == \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e) ? \u003cspan class=\"pl-c1\"\u003enull\u003c/span\u003e : \u003cspan class=\"pl-en\"\u003edequeue\u003c/span\u003e();\n        } \u003cspan class=\"pl-k\"\u003efinally\u003c/span\u003e {\n            \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eunlock\u003c/span\u003e();\n        }\n    }\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eadd\u003c/code\u003e 方法其实就是对于 \u003ccode\u003eoffer\u003c/code\u003e 做了一层封装，如下代码所示，可以看到 \u003ccode\u003eadd\u003c/code\u003e 会调用没有规定时间的 \u003ccode\u003eoffer\u003c/code\u003e，如果入队失败则直接抛异常。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public boolean add(E e) {\n        return super.add(e);\n    }\n\n\npublic boolean add(E e) {\n        //调用offer方法如果失败直接抛出异常\n        if (offer(e))\n            return true;\n        else\n            throw new IllegalStateException(\u0026quot;Queue full\u0026quot;);\n    }\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e) {\n        \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003esuper\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e);\n    }\n\n\n\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eadd\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e) {\n        \u003cspan class=\"pl-c\"\u003e//调用offer方法如果失败直接抛出异常\u003c/span\u003e\n        \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-en\"\u003eoffer\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e))\n            \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e;\n        \u003cspan class=\"pl-k\"\u003eelse\u003c/span\u003e\n            \u003cspan class=\"pl-k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eIllegalStateException\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"Queue full\"\u003c/span\u003e);\n    }\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eremove\u003c/code\u003e 方法同理，调用 \u003ccode\u003epoll\u003c/code\u003e，如果返回 \u003ccode\u003enull\u003c/code\u003e 则说明队列没有元素，直接抛出异常。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public E remove() {\n        E x = poll();\n        if (x != null)\n            return x;\n        else\n            throw new NoSuchElementException();\n    }\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eremove\u003c/span\u003e() {\n        \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ex\u003c/span\u003e = \u003cspan class=\"pl-en\"\u003epoll\u003c/span\u003e();\n        \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ex\u003c/span\u003e != \u003cspan class=\"pl-c1\"\u003enull\u003c/span\u003e)\n            \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ex\u003c/span\u003e;\n        \u003cspan class=\"pl-k\"\u003eelse\u003c/span\u003e\n            \u003cspan class=\"pl-k\"\u003ethrow\u003c/span\u003e \u003cspan class=\"pl-k\"\u003enew\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eNoSuchElementException\u003c/span\u003e();\n    }\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003epeek()\u003c/code\u003e 方法的逻辑也很简单，内部调用了 \u003ccode\u003eitemAt\u003c/code\u003e 方法。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public E peek() {\n        //加锁\n        final ReentrantLock lock = this.lock;\n        lock.lock();\n        try {\n            //当队列为空时返回 null\n            return itemAt(takeIndex);\n        } finally {\n            //释放锁\n            lock.unlock();\n        }\n    }\n\n//返回队列中指定位置的元素\n@SuppressWarnings(\u0026quot;unchecked\u0026quot;)\nfinal E itemAt(int i) {\n    return (E) items[i];\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-en\"\u003epeek\u003c/span\u003e() {\n        \u003cspan class=\"pl-c\"\u003e//加锁\u003c/span\u003e\n        \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eReentrantLock\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e;\n        \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003elock\u003c/span\u003e();\n        \u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e {\n            \u003cspan class=\"pl-c\"\u003e//当队列为空时返回 null\u003c/span\u003e\n            \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eitemAt\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003etakeIndex\u003c/span\u003e);\n        } \u003cspan class=\"pl-k\"\u003efinally\u003c/span\u003e {\n            \u003cspan class=\"pl-c\"\u003e//释放锁\u003c/span\u003e\n            \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eunlock\u003c/span\u003e();\n        }\n    }\n\n\u003cspan class=\"pl-c\"\u003e//返回队列中指定位置的元素\u003c/span\u003e\n\u003cspan class=\"pl-c1\"\u003e@\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003eSuppressWarnings\u003c/span\u003e(\u003cspan class=\"pl-s\"\u003e\"unchecked\"\u003c/span\u003e)\n\u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eitemAt\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e) {\n    \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e (\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e) \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e[\u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e];\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e指定超时时间内阻塞式获取和新增元素\u003c/h3\u003e\u003ca id=\"user-content-指定超时时间内阻塞式获取和新增元素\" class=\"anchor\" aria-label=\"Permalink: 指定超时时间内阻塞式获取和新增元素\" href=\"#指定超时时间内阻塞式获取和新增元素\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e在 \u003ccode\u003eoffer(E e)\u003c/code\u003e 和 \u003ccode\u003epoll()\u003c/code\u003e 非阻塞获取和新增元素的基础上，设计者提供了带有等待时间的 \u003ccode\u003eoffer(E e, long timeout, TimeUnit unit)\u003c/code\u003e 和 \u003ccode\u003epoll(long timeout, TimeUnit unit)\u003c/code\u003e ，用于在指定的超时时间内阻塞式地添加和获取元素。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\" public boolean offer(E e, long timeout, TimeUnit unit)\n        throws InterruptedException {\n\n        checkNotNull(e);\n        long nanos = unit.toNanos(timeout);\n        final ReentrantLock lock = this.lock;\n        lock.lockInterruptibly();\n        try {\n        //队列已满，进入循环\n            while (count == items.length) {\n            //时间到了队列还是满的，则直接返回false\n                if (nanos \u0026lt;= 0)\n                    return false;\n                 //阻塞nanos时间，等待非满\n                nanos = notFull.awaitNanos(nanos);\n            }\n            enqueue(e);\n            return true;\n        } finally {\n            lock.unlock();\n        }\n    }\"\u003e\u003cpre\u003e \u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-en\"\u003eoffer\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e, \u003cspan class=\"pl-smi\"\u003elong\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003etimeout\u003c/span\u003e, \u003cspan class=\"pl-smi\"\u003eTimeUnit\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eunit\u003c/span\u003e)\n        \u003cspan class=\"pl-k\"\u003ethrows\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eInterruptedException\u003c/span\u003e {\n\n        \u003cspan class=\"pl-en\"\u003echeckNotNull\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e);\n        \u003cspan class=\"pl-smi\"\u003elong\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003enanos\u003c/span\u003e = \u003cspan class=\"pl-s1\"\u003eunit\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003etoNanos\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003etimeout\u003c/span\u003e);\n        \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eReentrantLock\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e;\n        \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003elockInterruptibly\u003c/span\u003e();\n        \u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e {\n        \u003cspan class=\"pl-c\"\u003e//队列已满，进入循环\u003c/span\u003e\n            \u003cspan class=\"pl-k\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e == \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elength\u003c/span\u003e) {\n            \u003cspan class=\"pl-c\"\u003e//时间到了队列还是满的，则直接返回false\u003c/span\u003e\n                \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003enanos\u003c/span\u003e \u0026lt;= \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e)\n                    \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003efalse\u003c/span\u003e;\n                 \u003cspan class=\"pl-c\"\u003e//阻塞nanos时间，等待非满\u003c/span\u003e\n                \u003cspan class=\"pl-s1\"\u003enanos\u003c/span\u003e = \u003cspan class=\"pl-s1\"\u003enotFull\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eawaitNanos\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003enanos\u003c/span\u003e);\n            }\n            \u003cspan class=\"pl-en\"\u003eenqueue\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003ee\u003c/span\u003e);\n            \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e;\n        } \u003cspan class=\"pl-k\"\u003efinally\u003c/span\u003e {\n            \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eunlock\u003c/span\u003e();\n        }\n    }\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e可以看到，带有超时时间的 \u003ccode\u003eoffer\u003c/code\u003e 方法在队列已满的情况下，会等待用户所传的时间段，如果规定时间内还不能存放元素则直接返回 \u003ccode\u003efalse\u003c/code\u003e。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public E poll(long timeout, TimeUnit unit) throws InterruptedException {\n        long nanos = unit.toNanos(timeout);\n        final ReentrantLock lock = this.lock;\n        lock.lockInterruptibly();\n        try {\n          //队列为空，循环等待，若时间到还是空的，则直接返回null\n            while (count == 0) {\n                if (nanos \u0026lt;= 0)\n                    return null;\n                nanos = notEmpty.awaitNanos(nanos);\n            }\n            return dequeue();\n        } finally {\n            lock.unlock();\n        }\n    }\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eE\u003c/span\u003e \u003cspan class=\"pl-en\"\u003epoll\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003elong\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003etimeout\u003c/span\u003e, \u003cspan class=\"pl-smi\"\u003eTimeUnit\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eunit\u003c/span\u003e) \u003cspan class=\"pl-k\"\u003ethrows\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eInterruptedException\u003c/span\u003e {\n        \u003cspan class=\"pl-smi\"\u003elong\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003enanos\u003c/span\u003e = \u003cspan class=\"pl-s1\"\u003eunit\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003etoNanos\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003etimeout\u003c/span\u003e);\n        \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eReentrantLock\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e;\n        \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003elockInterruptibly\u003c/span\u003e();\n        \u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e {\n          \u003cspan class=\"pl-c\"\u003e//队列为空，循环等待，若时间到还是空的，则直接返回null\u003c/span\u003e\n            \u003cspan class=\"pl-k\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e == \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e) {\n                \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003enanos\u003c/span\u003e \u0026lt;= \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e)\n                    \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003enull\u003c/span\u003e;\n                \u003cspan class=\"pl-s1\"\u003enanos\u003c/span\u003e = \u003cspan class=\"pl-s1\"\u003enotEmpty\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eawaitNanos\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003enanos\u003c/span\u003e);\n            }\n            \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-en\"\u003edequeue\u003c/span\u003e();\n        } \u003cspan class=\"pl-k\"\u003efinally\u003c/span\u003e {\n            \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eunlock\u003c/span\u003e();\n        }\n    }\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e同理，带有超时时间的 \u003ccode\u003epoll\u003c/code\u003e 也一样，队列为空则在规定时间内等待，若时间到了还是空的，则直接返回 null。\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e判断元素是否存在\u003c/h3\u003e\u003ca id=\"user-content-判断元素是否存在\" class=\"anchor\" aria-label=\"Permalink: 判断元素是否存在\" href=\"#判断元素是否存在\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 提供了 \u003ccode\u003econtains(Object o)\u003c/code\u003e 来判断指定元素是否存在于队列中。\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-java notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"public boolean contains(Object o) {\n    //若目标元素为空，则直接返回 false\n    if (o == null) return false;\n    //获取当前队列的元素数组\n    final Object[] items = this.items;\n    //加锁\n    final ReentrantLock lock = this.lock;\n    lock.lock();\n    try {\n        // 如果队列非空\n        if (count \u0026gt; 0) {\n            final int putIndex = this.putIndex;\n            //从队列头部开始遍历\n            int i = takeIndex;\n            do {\n                if (o.equals(items[i]))\n                    return true;\n                if (++i == items.length)\n                    i = 0;\n            } while (i != putIndex);\n        }\n        return false;\n    } finally {\n        //释放锁\n        lock.unlock();\n    }\n}\"\u003e\u003cpre\u003e\u003cspan class=\"pl-k\"\u003epublic\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eboolean\u003c/span\u003e \u003cspan class=\"pl-en\"\u003econtains\u003c/span\u003e(\u003cspan class=\"pl-smi\"\u003eObject\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eo\u003c/span\u003e) {\n    \u003cspan class=\"pl-c\"\u003e//若目标元素为空，则直接返回 false\u003c/span\u003e\n    \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003eo\u003c/span\u003e == \u003cspan class=\"pl-c1\"\u003enull\u003c/span\u003e) \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003efalse\u003c/span\u003e;\n    \u003cspan class=\"pl-c\"\u003e//获取当前队列的元素数组\u003c/span\u003e\n    \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eObject\u003c/span\u003e[] \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e;\n    \u003cspan class=\"pl-c\"\u003e//加锁\u003c/span\u003e\n    \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eReentrantLock\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e;\n    \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003elock\u003c/span\u003e();\n    \u003cspan class=\"pl-k\"\u003etry\u003c/span\u003e {\n        \u003cspan class=\"pl-c\"\u003e// 如果队列非空\u003c/span\u003e\n        \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ecount\u003c/span\u003e \u0026gt; \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e) {\n            \u003cspan class=\"pl-k\"\u003efinal\u003c/span\u003e \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003eputIndex\u003c/span\u003e = \u003cspan class=\"pl-smi\"\u003ethis\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003eputIndex\u003c/span\u003e;\n            \u003cspan class=\"pl-c\"\u003e//从队列头部开始遍历\u003c/span\u003e\n            \u003cspan class=\"pl-smi\"\u003eint\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e = \u003cspan class=\"pl-s1\"\u003etakeIndex\u003c/span\u003e;\n            \u003cspan class=\"pl-k\"\u003edo\u003c/span\u003e {\n                \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003eo\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eequals\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e[\u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e]))\n                    \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003etrue\u003c/span\u003e;\n                \u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (++\u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e == \u003cspan class=\"pl-s1\"\u003eitems\u003c/span\u003e.\u003cspan class=\"pl-s1\"\u003elength\u003c/span\u003e)\n                    \u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e = \u003cspan class=\"pl-c1\"\u003e0\u003c/span\u003e;\n            } \u003cspan class=\"pl-k\"\u003ewhile\u003c/span\u003e (\u003cspan class=\"pl-s1\"\u003ei\u003c/span\u003e != \u003cspan class=\"pl-s1\"\u003eputIndex\u003c/span\u003e);\n        }\n        \u003cspan class=\"pl-k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003efalse\u003c/span\u003e;\n    } \u003cspan class=\"pl-k\"\u003efinally\u003c/span\u003e {\n        \u003cspan class=\"pl-c\"\u003e//释放锁\u003c/span\u003e\n        \u003cspan class=\"pl-s1\"\u003elock\u003c/span\u003e.\u003cspan class=\"pl-en\"\u003eunlock\u003c/span\u003e();\n    }\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eArrayBlockingQueue 获取和新增元素的方法对比\u003c/h2\u003e\u003ca id=\"user-content-arrayblockingqueue-获取和新增元素的方法对比\" class=\"anchor\" aria-label=\"Permalink: ArrayBlockingQueue 获取和新增元素的方法对比\" href=\"#arrayblockingqueue-获取和新增元素的方法对比\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e为了帮助理解 \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e ，我们再来对比一下上面提到的这些获取和新增元素的方法。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e新增元素：\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e方法\u003c/th\u003e\n\u003cth\u003e队列满时处理方式\u003c/th\u003e\n\u003cth\u003e方法返回值\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eput(E e)\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e线程阻塞，直到中断或被唤醒\u003c/td\u003e\n\u003ctd\u003evoid\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eoffer(E e)\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e直接返回 false\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eoffer(E e, long timeout, TimeUnit unit)\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e指定超时时间内阻塞，超过规定时间还未添加成功则返回 false\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eadd(E e)\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e直接抛出 \u003ccode\u003eIllegalStateException\u003c/code\u003e 异常\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003e获取/移除元素：\u003c/p\u003e\n\u003cmarkdown-accessiblity-table\u003e\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth\u003e方法\u003c/th\u003e\n\u003cth\u003e队列空时处理方式\u003c/th\u003e\n\u003cth\u003e方法返回值\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003etake()\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e线程阻塞，直到中断或被唤醒\u003c/td\u003e\n\u003ctd\u003eE\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003epoll()\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e返回 null\u003c/td\u003e\n\u003ctd\u003eE\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003epoll(long timeout, TimeUnit unit)\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e指定超时时间内阻塞，超过规定时间还是空的则返回 null\u003c/td\u003e\n\u003ctd\u003eE\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003epeek()\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e返回 null\u003c/td\u003e\n\u003ctd\u003eE\u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003ccode\u003eremove()\u003c/code\u003e\u003c/td\u003e\n\u003ctd\u003e直接抛出 \u003ccode\u003eNoSuchElementException\u003c/code\u003e 异常\u003c/td\u003e\n\u003ctd\u003eboolean\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\u003c/markdown-accessiblity-table\u003e\n\u003cp dir=\"auto\"\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"https://camo.githubusercontent.com/09b66774ef1ad6fdfeec1b3e178474d1a33222fb85e3f399026d4e4a5f79f1cc/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6765742d6164642d656c656d656e742d6d6574686f64732e706e67\"\u003e\u003cimg src=\"https://camo.githubusercontent.com/09b66774ef1ad6fdfeec1b3e178474d1a33222fb85e3f399026d4e4a5f79f1cc/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6765742d6164642d656c656d656e742d6d6574686f64732e706e67\" alt=\"\" data-canonical-src=\"https://oss.javaguide.cn/github/javaguide/java/collection/ArrayBlockingQueue-get-add-element-methods.png\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eArrayBlockingQueue 相关面试题\u003c/h2\u003e\u003ca id=\"user-content-arrayblockingqueue-相关面试题\" class=\"anchor\" aria-label=\"Permalink: ArrayBlockingQueue 相关面试题\" href=\"#arrayblockingqueue-相关面试题\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eArrayBlockingQueue 是什么？它的特点是什么？\u003c/h3\u003e\u003ca id=\"user-content-arrayblockingqueue-是什么它的特点是什么\" class=\"anchor\" aria-label=\"Permalink: ArrayBlockingQueue 是什么？它的特点是什么？\" href=\"#arrayblockingqueue-是什么它的特点是什么\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 是 \u003ccode\u003eBlockingQueue\u003c/code\u003e 接口的有界队列实现类，常用于多线程之间的数据共享，底层采用数组实现，从其名字就能看出来了。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 的容量有限，一旦创建，容量不能改变。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e为了保证线程安全，\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 的并发控制采用可重入锁 \u003ccode\u003eReentrantLock\u003c/code\u003e ，不管是插入操作还是读取操作，都需要获取到锁才能进行操作。并且，它还支持公平和非公平两种方式的锁访问机制，默认是非公平锁。\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 虽名为阻塞队列，但也支持非阻塞获取和新增元素（例如 \u003ccode\u003epoll()\u003c/code\u003e 和 \u003ccode\u003eoffer(E e)\u003c/code\u003e 方法），只是队列满时添加元素会抛出异常，队列为空时获取的元素为 null，一般不会使用。\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别？\u003c/h3\u003e\u003ca id=\"user-content-arrayblockingqueue-和-linkedblockingqueue-有什么区别\" class=\"anchor\" aria-label=\"Permalink: ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别？\" href=\"#arrayblockingqueue-和-linkedblockingqueue-有什么区别\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 和 \u003ccode\u003eLinkedBlockingQueue\u003c/code\u003e 是 Java 并发包中常用的两种阻塞队列实现，它们都是线程安全的。不过，不过它们之间也存在下面这些区别：\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e底层实现：\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 基于数组实现，而 \u003ccode\u003eLinkedBlockingQueue\u003c/code\u003e 基于链表实现。\u003c/li\u003e\n\u003cli\u003e是否有界：\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 是有界队列，必须在创建时指定容量大小。\u003ccode\u003eLinkedBlockingQueue\u003c/code\u003e 创建时可以不指定容量大小，默认是\u003ccode\u003eInteger.MAX_VALUE\u003c/code\u003e，也就是无界的。但也可以指定队列大小，从而成为有界的。\u003c/li\u003e\n\u003cli\u003e锁是否分离： \u003ccode\u003eArrayBlockingQueue\u003c/code\u003e中的锁是没有分离的，即生产和消费用的是同一个锁；\u003ccode\u003eLinkedBlockingQueue\u003c/code\u003e中的锁是分离的，即生产用的是\u003ccode\u003eputLock\u003c/code\u003e，消费是\u003ccode\u003etakeLock\u003c/code\u003e，这样可以防止生产者和消费者线程之间的锁争夺。\u003c/li\u003e\n\u003cli\u003e内存占用：\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 需要提前分配数组内存，而 \u003ccode\u003eLinkedBlockingQueue\u003c/code\u003e 则是动态分配链表节点内存。这意味着，\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 在创建时就会占用一定的内存空间，且往往申请的内存比实际所用的内存更大，而\u003ccode\u003eLinkedBlockingQueue\u003c/code\u003e 则是根据元素的增加而逐渐占用内存空间。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eArrayBlockingQueue 和 ConcurrentLinkedQueue 有什么区别？\u003c/h3\u003e\u003ca id=\"user-content-arrayblockingqueue-和-concurrentlinkedqueue-有什么区别\" class=\"anchor\" aria-label=\"Permalink: ArrayBlockingQueue 和 ConcurrentLinkedQueue 有什么区别？\" href=\"#arrayblockingqueue-和-concurrentlinkedqueue-有什么区别\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 和 \u003ccode\u003eConcurrentLinkedQueue\u003c/code\u003e 是 Java 并发包中常用的两种队列实现，它们都是线程安全的。不过，不过它们之间也存在下面这些区别：\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e底层实现：\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 基于数组实现，而 \u003ccode\u003eConcurrentLinkedQueue\u003c/code\u003e 基于链表实现。\u003c/li\u003e\n\u003cli\u003e是否有界：\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 是有界队列，必须在创建时指定容量大小，而 \u003ccode\u003eConcurrentLinkedQueue\u003c/code\u003e 是无界队列，可以动态地增加容量。\u003c/li\u003e\n\u003cli\u003e是否阻塞：\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 支持阻塞和非阻塞两种获取和新增元素的方式（一般只会使用前者）， \u003ccode\u003eConcurrentLinkedQueue\u003c/code\u003e 是无界的，仅支持非阻塞式获取和新增元素。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eArrayBlockingQueue 的实现原理是什么？\u003c/h3\u003e\u003ca id=\"user-content-arrayblockingqueue-的实现原理是什么\" class=\"anchor\" aria-label=\"Permalink: ArrayBlockingQueue 的实现原理是什么？\" href=\"#arrayblockingqueue-的实现原理是什么\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 的实现原理主要分为以下几点（这里以阻塞式获取和新增元素为例介绍）：\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e\u003ccode\u003eArrayBlockingQueue\u003c/code\u003e 内部维护一个定长的数组用于存储元素。\u003c/li\u003e\n\u003cli\u003e通过使用 \u003ccode\u003eReentrantLock\u003c/code\u003e 锁对象对读写操作进行同步，即通过锁机制来实现线程安全。\u003c/li\u003e\n\u003cli\u003e通过 \u003ccode\u003eCondition\u003c/code\u003e 实现线程间的等待和唤醒操作。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e这里再详细介绍一下线程间的等待和唤醒具体的实现（不需要记具体的方法，面试中回答要点即可）：\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e当队列已满时，生产者线程会调用 \u003ccode\u003enotFull.await()\u003c/code\u003e 方法让生产者进行等待，等待队列非满时插入（非满条件）。\u003c/li\u003e\n\u003cli\u003e当队列为空时，消费者线程会调用 \u003ccode\u003enotEmpty.await()\u003c/code\u003e方法让消费者进行等待，等待队列非空时消费（非空条件）。\u003c/li\u003e\n\u003cli\u003e当有新的元素被添加时，生产者线程会调用 \u003ccode\u003enotEmpty.signal()\u003c/code\u003e方法唤醒正在等待消费的消费者线程。\u003c/li\u003e\n\u003cli\u003e当队列中有元素被取出时，消费者线程会调用 \u003ccode\u003enotFull.signal()\u003c/code\u003e方法唤醒正在等待插入元素的生产者线程。\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003e关于 \u003ccode\u003eCondition\u003c/code\u003e接口的补充：\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp dir=\"auto\"\u003e\u003ccode\u003eCondition\u003c/code\u003e是 JDK1.5 之后才有的，它具有很好的灵活性，比如可以实现多路通知功能也就是在一个\u003ccode\u003eLock\u003c/code\u003e对象中可以创建多个\u003ccode\u003eCondition\u003c/code\u003e实例（即对象监视器），\u003cstrong\u003e线程对象可以注册在指定的\u003ccode\u003eCondition\u003c/code\u003e中，从而可以有选择性的进行线程通知，在调度线程上更加灵活。 在使用\u003ccode\u003enotify()/notifyAll()\u003c/code\u003e方法进行通知时，被通知的线程是由 JVM 选择的，用\u003ccode\u003eReentrantLock\u003c/code\u003e类结合\u003ccode\u003eCondition\u003c/code\u003e实例可以实现“选择性通知”\u003c/strong\u003e ，这个功能非常重要，而且是 \u003ccode\u003eCondition\u003c/code\u003e 接口默认提供的。而\u003ccode\u003esynchronized\u003c/code\u003e关键字就相当于整个 \u003ccode\u003eLock\u003c/code\u003e 对象中只有一个\u003ccode\u003eCondition\u003c/code\u003e实例，所有的线程都注册在它一个身上。如果执行\u003ccode\u003enotifyAll()\u003c/code\u003e方法的话就会通知所有处于等待状态的线程，这样会造成很大的效率问题。而\u003ccode\u003eCondition\u003c/code\u003e实例的\u003ccode\u003esignalAll()\u003c/code\u003e方法，只会唤醒注册在该\u003ccode\u003eCondition\u003c/code\u003e实例中的所有等待线程。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003e参考文献\u003c/h2\u003e\u003ca id=\"user-content-参考文献\" class=\"anchor\" aria-label=\"Permalink: 参考文献\" href=\"#参考文献\"\u003e\u003csvg data-component=\"Octicon\" class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003e深入理解 Java 系列 | BlockingQueue 用法详解：\u003ca href=\"https://juejin.cn/post/6999798721269465102\" rel=\"nofollow\"\u003ehttps://juejin.cn/post/6999798721269465102\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e深入浅出阻塞队列 BlockingQueue 及其典型实现 ArrayBlockingQueue：\u003ca href=\"https://zhuanlan.zhihu.com/p/539619957\" rel=\"nofollow\"\u003ehttps://zhuanlan.zhihu.com/p/539619957\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e并发编程大扫盲：ArrayBlockingQueue 底层原理和实战：\u003ca href=\"https://zhuanlan.zhihu.com/p/339662987\" rel=\"nofollow\"\u003ehttps://zhuanlan.zhihu.com/p/339662987\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003c/article\u003e","richTextTruncated":false,"renderedFileInfo":null,"symbols":{"timed_out":false,"not_analyzed":false,"symbols":[{"name":"阻塞队列简介","fully_qualified_name":"阻塞队列简介","kind":"section_2","ident_start":86,"ident_end":104,"extent_start":83,"extent_end":3202,"ident_utf16":{"start":{"line_number":7,"utf16_col":3},"end":{"line_number":7,"utf16_col":9}},"extent_utf16":{"start":{"line_number":7,"utf16_col":0},"end":{"line_number":44,"utf16_col":0}}},{"name":"阻塞队列的历史","fully_qualified_name":"阻塞队列的历史","kind":"section_3","ident_start":110,"ident_end":131,"extent_start":106,"extent_end":1548,"ident_utf16":{"start":{"line_number":9,"utf16_col":4},"end":{"line_number":9,"utf16_col":11}},"extent_utf16":{"start":{"line_number":9,"utf16_col":0},"end":{"line_number":21,"utf16_col":0}}},{"name":"阻塞队列的思想","fully_qualified_name":"阻塞队列的思想","kind":"section_3","ident_start":1552,"ident_end":1573,"extent_start":1548,"extent_end":3202,"ident_utf16":{"start":{"line_number":21,"utf16_col":4},"end":{"line_number":21,"utf16_col":11}},"extent_utf16":{"start":{"line_number":21,"utf16_col":0},"end":{"line_number":44,"utf16_col":0}}},{"name":"ArrayBlockingQueue 常见方法及测试","fully_qualified_name":"ArrayBlockingQueue 常见方法及测试","kind":"section_2","ident_start":3205,"ident_end":3245,"extent_start":3202,"extent_end":9361,"ident_utf16":{"start":{"line_number":44,"utf16_col":3},"end":{"line_number":44,"utf16_col":29}},"extent_utf16":{"start":{"line_number":44,"utf16_col":0},"end":{"line_number":218,"utf16_col":0}}},{"name":"ArrayBlockingQueue 源码分析","fully_qualified_name":"ArrayBlockingQueue 源码分析","kind":"section_2","ident_start":9364,"ident_end":9395,"extent_start":9361,"extent_end":30148,"ident_utf16":{"start":{"line_number":218,"utf16_col":3},"end":{"line_number":218,"utf16_col":26}},"extent_utf16":{"start":{"line_number":218,"utf16_col":0},"end":{"line_number":694,"utf16_col":0}}},{"name":"整体设计","fully_qualified_name":"整体设计","kind":"section_3","ident_start":9551,"ident_end":9563,"extent_start":9547,"extent_end":14481,"ident_utf16":{"start":{"line_number":222,"utf16_col":4},"end":{"line_number":222,"utf16_col":8}},"extent_utf16":{"start":{"line_number":222,"utf16_col":0},"end":{"line_number":316,"utf16_col":0}}},{"name":"初始化","fully_qualified_name":"初始化","kind":"section_3","ident_start":14485,"ident_end":14494,"extent_start":14481,"extent_end":17177,"ident_utf16":{"start":{"line_number":316,"utf16_col":4},"end":{"line_number":316,"utf16_col":7}},"extent_utf16":{"start":{"line_number":316,"utf16_col":0},"end":{"line_number":379,"utf16_col":0}}},{"name":"阻塞式获取和新增元素","fully_qualified_name":"阻塞式获取和新增元素","kind":"section_3","ident_start":17181,"ident_end":17211,"extent_start":17177,"extent_end":24115,"ident_utf16":{"start":{"line_number":379,"utf16_col":4},"end":{"line_number":379,"utf16_col":14}},"extent_utf16":{"start":{"line_number":379,"utf16_col":0},"end":{"line_number":505,"utf16_col":0}}},{"name":"非阻塞式获取和新增元素","fully_qualified_name":"非阻塞式获取和新增元素","kind":"section_3","ident_start":24119,"ident_end":24152,"extent_start":24115,"extent_end":27303,"ident_utf16":{"start":{"line_number":505,"utf16_col":4},"end":{"line_number":505,"utf16_col":15}},"extent_utf16":{"start":{"line_number":505,"utf16_col":0},"end":{"line_number":608,"utf16_col":0}}},{"name":"指定超时时间内阻塞式获取和新增元素","fully_qualified_name":"指定超时时间内阻塞式获取和新增元素","kind":"section_3","ident_start":27307,"ident_end":27358,"extent_start":27303,"extent_end":29251,"ident_utf16":{"start":{"line_number":608,"utf16_col":4},"end":{"line_number":608,"utf16_col":21}},"extent_utf16":{"start":{"line_number":608,"utf16_col":0},"end":{"line_number":660,"utf16_col":0}}},{"name":"判断元素是否存在","fully_qualified_name":"判断元素是否存在","kind":"section_3","ident_start":29255,"ident_end":29279,"extent_start":29251,"extent_end":30148,"ident_utf16":{"start":{"line_number":660,"utf16_col":4},"end":{"line_number":660,"utf16_col":12}},"extent_utf16":{"start":{"line_number":660,"utf16_col":0},"end":{"line_number":694,"utf16_col":0}}},{"name":"ArrayBlockingQueue 获取和新增元素的方法对比","fully_qualified_name":"ArrayBlockingQueue 获取和新增元素的方法对比","kind":"section_2","ident_start":30151,"ident_end":30206,"extent_start":30148,"extent_end":32066,"ident_utf16":{"start":{"line_number":694,"utf16_col":3},"end":{"line_number":694,"utf16_col":34}},"extent_utf16":{"start":{"line_number":694,"utf16_col":0},"end":{"line_number":719,"utf16_col":0}}},{"name":"ArrayBlockingQueue 相关面试题","fully_qualified_name":"ArrayBlockingQueue 相关面试题","kind":"section_2","ident_start":32069,"ident_end":32103,"extent_start":32066,"extent_end":37120,"ident_utf16":{"start":{"line_number":719,"utf16_col":3},"end":{"line_number":719,"utf16_col":27}},"extent_utf16":{"start":{"line_number":719,"utf16_col":0},"end":{"line_number":767,"utf16_col":0}}},{"name":"ArrayBlockingQueue 是什么？它的特点是什么？","fully_qualified_name":"ArrayBlockingQueue 是什么？它的特点是什么？","kind":"section_3","ident_start":32109,"ident_end":32164,"extent_start":32105,"extent_end":32951,"ident_utf16":{"start":{"line_number":721,"utf16_col":4},"end":{"line_number":721,"utf16_col":35}},"extent_utf16":{"start":{"line_number":721,"utf16_col":0},"end":{"line_number":731,"utf16_col":0}}},{"name":"ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别？","fully_qualified_name":"ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别？","kind":"section_3","ident_start":32955,"ident_end":33016,"extent_start":32951,"extent_end":34222,"ident_utf16":{"start":{"line_number":731,"utf16_col":4},"end":{"line_number":731,"utf16_col":51}},"extent_utf16":{"start":{"line_number":731,"utf16_col":0},"end":{"line_number":740,"utf16_col":0}}},{"name":"ArrayBlockingQueue 和 ConcurrentLinkedQueue 有什么区别？","fully_qualified_name":"ArrayBlockingQueue 和 ConcurrentLinkedQueue 有什么区别？","kind":"section_3","ident_start":34226,"ident_end":34289,"extent_start":34222,"extent_end":34979,"ident_utf16":{"start":{"line_number":740,"utf16_col":4},"end":{"line_number":740,"utf16_col":53}},"extent_utf16":{"start":{"line_number":740,"utf16_col":0},"end":{"line_number":748,"utf16_col":0}}},{"name":"ArrayBlockingQueue 的实现原理是什么？","fully_qualified_name":"ArrayBlockingQueue 的实现原理是什么？","kind":"section_3","ident_start":34983,"ident_end":35029,"extent_start":34979,"extent_end":37120,"ident_utf16":{"start":{"line_number":748,"utf16_col":4},"end":{"line_number":748,"utf16_col":32}},"extent_utf16":{"start":{"line_number":748,"utf16_col":0},"end":{"line_number":767,"utf16_col":0}}},{"name":"参考文献","fully_qualified_name":"参考文献","kind":"section_2","ident_start":37123,"ident_end":37135,"extent_start":37120,"extent_end":37518,"ident_utf16":{"start":{"line_number":767,"utf16_col":3},"end":{"line_number":767,"utf16_col":7}},"extent_utf16":{"start":{"line_number":767,"utf16_col":0},"end":{"line_number":773,"utf16_col":0}}}]}},"codeViewLayoutRoute":{"repo":{"id":758919476,"defaultBranch":"main","name":"JavaGuide","ownerLogin":"cht37","currentUserCanPush":false,"isFork":true,"isEmpty":false,"createdAt":"2024-02-17T13:17:33.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/92900292?v=4","public":true,"private":false,"isOrgOwned":false,"isArchived":false},"currentUser":null,"uploadToken":"fj3Aa9oE77qYvLaVTDv6sMLT99vcyp_ZDhZa5gWXTt5mrxzCvRPoVaBrbH8BziSReMN2fmbJJIxLdy3Fi6Wf-w","allShortcutsEnabled":false,"treeExpanded":true,"path":"docs/java/collection/arrayblockingqueue-source-code.md","symbolsExpanded":false,"refInfo":{"name":"main","listCacheKey":"v0:1708175859.922521","canEdit":false,"currentOid":"f77a1467445bbfb0fce85306079c013883ed2203"},"helpUrl":"https://docs.github.com","githubDevUrl":null},"codeViewFileTreeLayoutRoute":{"fileTree":{"docs/java/collection":{"items":[{"name":"arrayblockingqueue-source-code.md","path":"docs/java/collection/arrayblockingqueue-source-code.md","contentType":"file"},{"name":"arraylist-source-code.md","path":"docs/java/collection/arraylist-source-code.md","contentType":"file"},{"name":"concurrent-hash-map-source-code.md","path":"docs/java/collection/concurrent-hash-map-source-code.md","contentType":"file"},{"name":"copyonwritearraylist-source-code.md","path":"docs/java/collection/copyonwritearraylist-source-code.md","contentType":"file"},{"name":"delayqueue-source-code.md","path":"docs/java/collection/delayqueue-source-code.md","contentType":"file"},{"name":"hashmap-source-code.md","path":"docs/java/collection/hashmap-source-code.md","contentType":"file"},{"name":"java-collection-precautions-for-use.md","path":"docs/java/collection/java-collection-precautions-for-use.md","contentType":"file"},{"name":"java-collection-questions-01.md","path":"docs/java/collection/java-collection-questions-01.md","contentType":"file"},{"name":"java-collection-questions-02.md","path":"docs/java/collection/java-collection-questions-02.md","contentType":"file"},{"name":"linkedhashmap-source-code.md","path":"docs/java/collection/linkedhashmap-source-code.md","contentType":"file"},{"name":"linkedlist-source-code.md","path":"docs/java/collection/linkedlist-source-code.md","contentType":"file"},{"name":"priorityqueue-source-code.md","path":"docs/java/collection/priorityqueue-source-code.md","contentType":"file"}],"totalCount":12},"docs/java":{"items":[{"name":"basis","path":"docs/java/basis","contentType":"directory"},{"name":"collection","path":"docs/java/collection","contentType":"directory"},{"name":"concurrent","path":"docs/java/concurrent","contentType":"directory"},{"name":"io","path":"docs/java/io","contentType":"directory"},{"name":"jvm","path":"docs/java/jvm","contentType":"directory"},{"name":"new-features","path":"docs/java/new-features","contentType":"directory"}],"totalCount":6},"docs":{"items":[{"name":".vuepress","path":"docs/.vuepress","contentType":"directory"},{"name":"about-the-author","path":"docs/about-the-author","contentType":"directory"},{"name":"books","path":"docs/books","contentType":"directory"},{"name":"cs-basics","path":"docs/cs-basics","contentType":"directory"},{"name":"database","path":"docs/database","contentType":"directory"},{"name":"distributed-system","path":"docs/distributed-system","contentType":"directory"},{"name":"high-availability","path":"docs/high-availability","contentType":"directory"},{"name":"high-performance","path":"docs/high-performance","contentType":"directory"},{"name":"high-quality-technical-articles","path":"docs/high-quality-technical-articles","contentType":"directory"},{"name":"interview-preparation","path":"docs/interview-preparation","contentType":"directory"},{"name":"java","path":"docs/java","contentType":"directory"},{"name":"javaguide","path":"docs/javaguide","contentType":"directory"},{"name":"open-source-project","path":"docs/open-source-project","contentType":"directory"},{"name":"snippets","path":"docs/snippets","contentType":"directory"},{"name":"system-design","path":"docs/system-design","contentType":"directory"},{"name":"tools","path":"docs/tools","contentType":"directory"},{"name":"zhuanlan","path":"docs/zhuanlan","contentType":"directory"},{"name":"home.md","path":"docs/home.md","contentType":"file"},{"name":"readme.md","path":"docs/readme.md","contentType":"file"}],"totalCount":19},"":{"items":[{"name":".github","path":".github","contentType":"directory"},{"name":".husky","path":".husky","contentType":"directory"},{"name":"docs","path":"docs","contentType":"directory"},{"name":"media","path":"media","contentType":"directory"},{"name":".gitattributes","path":".gitattributes","contentType":"file"},{"name":".gitignore","path":".gitignore","contentType":"file"},{"name":".markdownlint-cli2.mjs","path":".markdownlint-cli2.mjs","contentType":"file"},{"name":".nojekyll","path":".nojekyll","contentType":"file"},{"name":".prettierignore","path":".prettierignore","contentType":"file"},{"name":"LICENSE","path":"LICENSE","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"},{"name":"index.html","path":"index.html","contentType":"file"},{"name":"package.json","path":"package.json","contentType":"file"},{"name":"pnpm-lock.yaml","path":"pnpm-lock.yaml","contentType":"file"},{"name":"sw.js","path":"sw.js","contentType":"file"}],"totalCount":15}},"fileTreeProcessingTime":84.795838,"foldersToFetch":[]},"codeViewBlobLayoutRoute":{"codeLineWrapEnabled":false,"refInfo":{"name":"main","listCacheKey":"v0:1708175859.922521","canEdit":false,"refType":"branch","currentOid":"f77a1467445bbfb0fce85306079c013883ed2203","canEditOnDefaultBranch":false,"fileExistsOnDefault":true},"path":"docs/java/collection/arrayblockingqueue-source-code.md","blob":{"copilotSWEAgentEnabled":false,"dependabotInfo":{"showConfigurationBanner":false,"configFilePath":null,"networkDependabotPath":"/cht37/JavaGuide/network/updates","dismissConfigurationNoticePath":"/settings/dismiss-notice/dependabot_configuration_notice","configurationNoticeDismissed":null},"displayName":"arrayblockingqueue-source-code.md","displayUrl":"https://github.com/cht37/JavaGuide/blob/main/docs/java/collection/arrayblockingqueue-source-code.md?raw=true","headerInfo":{"blobSize":"36.6 KB","deleteTooltip":"You must be signed in to make or propose changes","editTooltip":"You must be signed in to make or propose changes","ghDesktopPath":"https://desktop.github.com","isGitLfs":false,"onBranch":true,"shortPath":"a1c6897","siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Fcht37%2FJavaGuide%2Fblob%2Fmain%2Fdocs%2Fjava%2Fcollection%2Farrayblockingqueue-source-code.md","isCSV":false,"isRichtext":true,"lineInfo":{"truncatedLoc":"773","truncatedSloc":"602"},"mode":"file"},"image":false,"isCodeownersFile":null,"isPlain":false,"isValidLegacyIssueTemplate":false,"isIssueTemplate":false,"isDiscussionTemplate":false,"language":"Markdown","languageID":222,"large":false,"planSupportInfo":{"repoIsFork":null,"repoOwnedByCurrentUser":null,"requestFullPath":"/cht37/JavaGuide/blob/main/docs/java/collection/arrayblockingqueue-source-code.md","showFreeOrgGatedFeatureMessage":null,"showPlanSupportBanner":null,"upgradeDataAttributes":null,"upgradePath":null},"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_dockerfile","releasePath":"/cht37/JavaGuide/releases/new?marketplace=true","showPublishActionBanner":false},"rawBlobUrl":"https://github.com/cht37/JavaGuide/raw/refs/heads/main/docs/java/collection/arrayblockingqueue-source-code.md","renderImageOrRaw":false,"shortPath":null,"symbolsEnabled":true,"tabSize":4,"topBannersInfo":{"overridingGlobalFundingFile":false,"globalPreferredFundingPath":null,"showInvalidCitationWarning":false,"citationHelpUrl":"https://docs.github.com/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-citation-files","actionsOnboardingTip":null},"truncated":false,"viewable":true,"workflowRedirectUrl":null},"copilotInfo":null,"copilotAccessAllowed":false,"copilotSpacesEnabled":false,"modelsAccessAllowed":false,"modelsRepoIntegrationEnabled":false,"isMarketplaceEnabled":true},"codeViewBlobLayoutRoute.StyledBlob":{"rawLines":["---","title: ArrayBlockingQueue 源码分析","category: Java","tag:","  - Java集合","---","","## 阻塞队列简介","","### 阻塞队列的历史","","Java 阻塞队列的历史可以追溯到 JDK1.5 版本，当时 Java 平台增加了 `java.util.concurrent`，即我们常说的 JUC 包，其中包含了各种并发流程控制工具、并发容器、原子类等。这其中自然也包含了我们这篇文章所讨论的阻塞队列。","","为了解决高并发场景下多线程之间数据共享的问题，JDK1.5 版本中出现了 `ArrayBlockingQueue` 和 `LinkedBlockingQueue`，它们是带有生产者-消费者模式实现的并发容器。其中，`ArrayBlockingQueue` 是有界队列，即添加的元素达到上限之后，再次添加就会被阻塞或者抛出异常。而 `LinkedBlockingQueue` 则由链表构成的队列，正是因为链表的特性，所以 `LinkedBlockingQueue` 在添加元素上并不会向 `ArrayBlockingQueue` 那样有着较多的约束，所以 `LinkedBlockingQueue` 设置队列是否有界是可选的(注意这里的无界并不是指可以添加任务数量的元素，而是说队列的大小默认为 `Integer.MAX_VALUE`，近乎于无限大)。","","随着 Java 的不断发展，JDK 后续的几个版本又对阻塞队列进行了不少的更新和完善:","","1. JDK1.6 版本:增加 `SynchronousQueue`，一个不存储元素的阻塞队列。","2. JDK1.7 版本:增加 `TransferQueue`，一个支持更多操作的阻塞队列。","3. JDK1.8 版本:增加 `DelayQueue`，一个支持延迟获取元素的阻塞队列。","","### 阻塞队列的思想","","阻塞队列就是典型的生产者-消费者模型，它可以做到以下几点:","","1. 当阻塞队列数据为空时，所有的消费者线程都会被阻塞，等待队列非空。","2. 当生产者往队列里填充数据后，队列就会通知消费者队列非空，消费者此时就可以进来消费。","3. 当阻塞队列因为消费者消费过慢或者生产者存放元素过快导致队列填满时无法容纳新元素时，生产者就会被阻塞，等待队列非满时继续存放元素。","4. 当消费者从队列中消费一个元素之后，队列就会通知生产者队列非满，生产者可以继续填充数据了。","","总结一下：阻塞队列就说基于非空和非满两个条件实现生产者和消费者之间的交互，尽管这些交互流程和等待通知的机制实现非常复杂，好在 Doug Lea 的操刀之下已将阻塞队列的细节屏蔽，我们只需调用 `put`、`take`、`offfer`、`poll` 等 API 即可实现多线程之间的生产和消费。","","这也使得阻塞队列在多线程开发中有着广泛的运用，最常见的例子无非是我们的线程池,从源码中我们就能看出当核心线程无法及时处理任务时，这些任务都会扔到 `workQueue` 中。","","```java","public ThreadPoolExecutor(int corePoolSize,","                            int maximumPoolSize,","                            long keepAliveTime,","                            TimeUnit unit,","                            BlockingQueue\u003cRunnable\u003e workQueue,","                            ThreadFactory threadFactory,","                            RejectedExecutionHandler handler) {// ...}","```","","## ArrayBlockingQueue 常见方法及测试","","简单了解了阻塞队列的历史之后，我们就开始重点讨论本篇文章所要介绍的并发容器——`ArrayBlockingQueue`。为了后续更加深入的了解 `ArrayBlockingQueue`，我们不妨基于下面几个实例了解以下 `ArrayBlockingQueue` 的使用。","","先看看第一个例子，我们这里会用两个线程分别模拟生产者和消费者，生产者生产完会使用 `put` 方法生产 10 个元素给消费者进行消费，当队列元素达到我们设置的上限 5 时，`put` 方法就会阻塞。","同理消费者也会通过 `take` 方法消费元素，当队列为空时，`take` 方法就会阻塞消费者线程。这里笔者为了保证消费者能够在消费完 10 个元素后及时退出。便通过倒计时门闩，来控制消费者结束，生产者在这里只会生产 10 个元素。当消费者将 10 个元素消费完成之后，按下倒计时门闩，所有线程都会停止。","","```java","public class ProducerConsumerExample {","","    public static void main(String[] args) throws InterruptedException {","","        // 创建一个大小为 5 的 ArrayBlockingQueue","        ArrayBlockingQueue\u003cInteger\u003e queue = new ArrayBlockingQueue\u003c\u003e(5);","","        // 创建生产者线程","        Thread producer = new Thread(() -\u003e {","            try {","                for (int i = 1; i \u003c= 10; i++) {","                    // 向队列中添加元素，如果队列已满则阻塞等待","                    queue.put(i);","                    System.out.println(\"生产者添加元素：\" + i);","                }","            } catch (InterruptedException e) {","                e.printStackTrace();","            }","","        });","","        CountDownLatch countDownLatch = new CountDownLatch(1);","","        // 创建消费者线程","        Thread consumer = new Thread(() -\u003e {","            try {","                int count = 0;","                while (true) {","","                    // 从队列中取出元素，如果队列为空则阻塞等待","                    int element = queue.take();","                    System.out.println(\"消费者取出元素：\" + element);","                    ++count;","                    if (count == 10) {","                        break;","                    }","                }","","                countDownLatch.countDown();","            } catch (InterruptedException e) {","                e.printStackTrace();","            }","","        });","","        // 启动线程","        producer.start();","        consumer.start();","","        // 等待线程结束","        producer.join();","        consumer.join();","","        countDownLatch.await();","","        producer.interrupt();","        consumer.interrupt();","    }","","}","```","","代码输出结果如下，可以看到只有生产者往队列中投放元素之后消费者才能消费，这也就意味着当队列中没有数据的时消费者就会阻塞，等待队列非空再继续消费。","","```cpp","生产者添加元素：1","生产者添加元素：2","消费者取出元素：1","消费者取出元素：2","消费者取出元素：3","生产者添加元素：3","生产者添加元素：4","生产者添加元素：5","消费者取出元素：4","生产者添加元素：6","消费者取出元素：5","生产者添加元素：7","生产者添加元素：8","生产者添加元素：9","生产者添加元素：10","消费者取出元素：6","消费者取出元素：7","消费者取出元素：8","消费者取出元素：9","消费者取出元素：10","```","","了解了 `put`、`take` 这两个会阻塞的存和取方法之后，我我们再来看看阻塞队列中非阻塞的入队和出队方法 `offer` 和 `poll`。","","如下所示，我们设置了一个大小为 3 的阻塞队列，我们会尝试在队列用 offer 方法存放 4 个元素，然后再从队列中用 `poll` 尝试取 4 次。","","```cpp","public class OfferPollExample {","","    public static void main(String[] args) {","        // 创建一个大小为 3 的 ArrayBlockingQueue","        ArrayBlockingQueue\u003cString\u003e queue = new ArrayBlockingQueue\u003c\u003e(3);","","        // 向队列中添加元素","        System.out.println(queue.offer(\"A\"));","        System.out.println(queue.offer(\"B\"));","        System.out.println(queue.offer(\"C\"));","","        // 尝试向队列中添加元素，但队列已满，返回 false","        System.out.println(queue.offer(\"D\"));","","        // 从队列中取出元素","        System.out.println(queue.poll());","        System.out.println(queue.poll());","        System.out.println(queue.poll());","","        // 尝试从队列中取出元素，但队列已空，返回 null","        System.out.println(queue.poll());","    }","","}","```","","最终代码的输出结果如下，可以看到因为队列的大小为 3 的缘故，我们前 3 次存放到队列的结果为 true，第 4 次存放时，由于队列已满，所以存放结果返回 false。这也是为什么我们后续的 `poll` 方法只得到了 3 个元素的值。","","```cpp","true","true","true","false","A","B","C","null","```","","了解了阻塞存取和非阻塞存取，我们再来看看阻塞队列的一个比较特殊的操作，某些场景下，我们希望能够一次性将阻塞队列的结果存到列表中再进行批量操作，我们就可以使用阻塞队列的 `drainTo` 方法，这个方法会一次性将队列中所有元素存放到列表，如果队列中有元素，且成功存到 list 中则 `drainTo` 会返回本次转移到 list 中的元素数，反之若队列为空，`drainTo` 则直接返回 0。","","```java","public class DrainToExample {","","    public static void main(String[] args) {","        // 创建一个大小为 5 的 ArrayBlockingQueue","        ArrayBlockingQueue\u003cInteger\u003e queue = new ArrayBlockingQueue\u003c\u003e(5);","","        // 向队列中添加元素","        queue.add(1);","        queue.add(2);","        queue.add(3);","        queue.add(4);","        queue.add(5);","","        // 创建一个 List，用于存储从队列中取出的元素","        List\u003cInteger\u003e list = new ArrayList\u003c\u003e();","","        // 从队列中取出所有元素，并添加到 List 中","        queue.drainTo(list);","","        // 输出 List 中的元素","        System.out.println(list);","    }","","}","```","","代码输出结果如下","","```cpp","[1, 2, 3, 4, 5]","```","","## ArrayBlockingQueue 源码分析","","自此我们对阻塞队列的使用有了基本的印象，接下来我们就可以进一步了解一下 `ArrayBlockingQueue` 的工作机制了。","","### 整体设计","","在了解 `ArrayBlockingQueue` 的具体细节之前，我们先来看看 `ArrayBlockingQueue` 的类图。","","![ArrayBlockingQueue 类图](https://oss.javaguide.cn/github/javaguide/java/collection/arrayblockingqueue-class-diagram.png)","","从图中我们可以看出，`ArrayBlockingQueue` 继承了阻塞队列 `BlockingQueue` 这个接口，不难猜出通过继承 `BlockingQueue` 这个接口之后，`ArrayBlockingQueue` 就拥有了阻塞队列那些常见的操作行为。","","同时， `ArrayBlockingQueue` 还继承了 `AbstractQueue` 这个抽象类，这个继承了 `AbstractCollection` 和 `Queue` 的抽象类，从抽象类的特定和语义我们也可以猜出，这个继承关系使得 `ArrayBlockingQueue` 拥有了队列的常见操作。","","所以我们是否可以得出这样一个结论，通过继承 `AbstractQueue` 获得队列所有的操作模板，其实现的入队和出队操作的整体框架。然后 `ArrayBlockingQueue` 通过继承 `BlockingQueue` 获取到阻塞队列的常见操作并将这些操作实现，填充到 `AbstractQueue` 模板方法的细节中，由此 `ArrayBlockingQueue` 成为一个完整的阻塞队列。","","为了印证这一点，我们到源码中一探究竟。首先我们先来看看 `AbstractQueue`，从类的继承关系我们可以大致得出，它通过 `AbstractCollection` 获得了集合的常见操作方法，然后通过 `Queue` 接口获得了队列的特性。","","```java","public abstract class AbstractQueue\u003cE\u003e","    extends AbstractCollection\u003cE\u003e","    implements Queue\u003cE\u003e {","       //...","}","```","","对于集合的操作无非是增删改查，所以我们不妨从添加方法入手，从源码中我们可以看到，它实现了 `AbstractCollection` 的 `add` 方法，其内部逻辑如下:","","1. 调用继承 `Queue` 接口的来的 `offer` 方法，如果 `offer` 成功则返回 `true`。","2. 如果 `offer` 失败，即代表当前元素入队失败直接抛异常。","","```java","public boolean add(E e) {","  if (offer(e))","      return true;","  else","      throw new IllegalStateException(\"Queue full\");","}","```","","而 `AbstractQueue` 中并没有对 `Queue` 的 `offer` 的实现，很明显这样做的目的是定义好了 `add` 的核心逻辑，将 `offer` 的细节交由其子类即我们的 `ArrayBlockingQueue` 实现。","","到此，我们对于抽象类 `AbstractQueue` 的分析就结束了，我们继续看看 `ArrayBlockingQueue` 中另一个重要的继承接口 `BlockingQueue`。","","点开 `BlockingQueue` 之后，我们可以看到这个接口同样继承了 `Queue` 接口，这就意味着它也具备了队列所拥有的所有行为。同时，它还定义了自己所需要实现的方法。","","```java","public interface BlockingQueue\u003cE\u003e extends Queue\u003cE\u003e {","","     //元素入队成功返回true，反之则会抛出异常IllegalStateException","    boolean add(E e);","","     //元素入队成功返回true，反之返回false","    boolean offer(E e);","","     //元素入队成功则直接返回，如果队列已满元素不可入队则将线程阻塞，因为阻塞期间可能会被打断，所以这里方法签名抛出了InterruptedException","    void put(E e) throws InterruptedException;","","   //和上一个方法一样,只不过队列满时只会阻塞单位为unit，时间为timeout的时长，如果在等待时长内没有入队成功则直接返回false。","    boolean offer(E e, long timeout, TimeUnit unit)","        throws InterruptedException;","","    //从队头取出一个元素，如果队列为空则阻塞等待，因为会阻塞线程的缘故，所以该方法可能会被打断，所以签名定义了InterruptedException","    E take() throws InterruptedException;","","      //取出队头的元素并返回，如果当前队列为空则阻塞等待timeout且单位为unit的时长，如果这个时间段没有元素则直接返回null。","    E poll(long timeout, TimeUnit unit)","        throws InterruptedException;","","      //获取队列剩余元素个数","    int remainingCapacity();","","     //删除我们指定的对象，如果成功返回true，反之返回false。","    boolean remove(Object o);","","    //判断队列中是否包含指定元素","    public boolean contains(Object o);","","     //将队列中的元素全部存到指定的集合中","    int drainTo(Collection\u003c? super E\u003e c);","","    //转移maxElements个元素到集合中","    int drainTo(Collection\u003c? super E\u003e c, int maxElements);","}","```","","了解了 `BlockingQueue` 的常见操作后，我们就知道了 `ArrayBlockingQueue` 通过继承 `BlockingQueue` 的方法并实现后，填充到 `AbstractQueue` 的方法上，由此我们便知道了上文中 `AbstractQueue` 的 `add` 方法的 `offer` 方法是哪里是实现的了。","","```java","public boolean add(E e) {","  //AbstractQueue的offer来自下层的ArrayBlockingQueue从BlockingQueue继承并实现的offer方法","  if (offer(e))","      return true;","  else","      throw new IllegalStateException(\"Queue full\");","}","```","","### 初始化","","了解 `ArrayBlockingQueue` 的细节前，我们不妨先看看其构造函数，了解一下其初始化过程。从源码中我们可以看出 `ArrayBlockingQueue` 有 3 个构造方法，而最核心的构造方法就是下方这一个。","","```java","// capacity 表示队列初始容量，fair 表示 锁的公平性","public ArrayBlockingQueue(int capacity, boolean fair) {","  //如果设置的队列大小小于0，则直接抛出IllegalArgumentException","  if (capacity \u003c= 0)","      throw new IllegalArgumentException();","  //初始化一个数组用于存放队列的元素","  this.items = new Object[capacity];","  //创建阻塞队列流程控制的锁","  lock = new ReentrantLock(fair);","  //用lock锁创建两个条件控制队列生产和消费","  notEmpty = lock.newCondition();","  notFull =  lock.newCondition();","}","```","","这个构造方法里面有两个比较核心的成员变量 `notEmpty`(非空) 和 `notFull` （非满） ，需要我们格外留意，它们是实现生产者和消费者有序工作的关键所在，这一点笔者会在后续的源码解析中详细说明，这里我们只需初步了解一下阻塞队列的构造即可。","","另外两个构造方法都是基于上述的构造方法，默认情况下，我们会使用下面这个构造方法，该构造方法就意味着 `ArrayBlockingQueue` 用的是非公平锁，即各个生产者或者消费者线程收到通知后，对于锁的争抢是随机的。","","```java"," public ArrayBlockingQueue(int capacity) {","        this(capacity, false);","    }","```","","还有一个不怎么常用的构造方法，在初始化容量和锁的非公平性之后，它还提供了一个 `Collection` 参数，从源码中不难看出这个构造方法是将外部传入的集合的元素在初始化时直接存放到阻塞队列中。","","```java","public ArrayBlockingQueue(int capacity, boolean fair,","                              Collection\u003c? extends E\u003e c) {","  //初始化容量和锁的公平性","  this(capacity, fair);","","  final ReentrantLock lock = this.lock;","  //上锁并将c中的元素存放到ArrayBlockingQueue底层的数组中","  lock.lock();","  try {","      int i = 0;","      try {","                //遍历并添加元素到数组中","          for (E e : c) {","              checkNotNull(e);","              items[i++] = e;","          }","      } catch (ArrayIndexOutOfBoundsException ex) {","          throw new IllegalArgumentException();","      }","      //记录当前队列容量","      count = i;","                      //更新下一次put或者offer或用add方法添加到队列底层数组的位置","      putIndex = (i == capacity) ? 0 : i;","  } finally {","      //完成遍历后释放锁","      lock.unlock();","  }","}","```","","### 阻塞式获取和新增元素","","`ArrayBlockingQueue` 阻塞式获取和新增元素对应的就是生产者-消费者模型，虽然它也支持非阻塞式获取和新增元素（例如 `poll()` 和 `offer(E e)` 方法，后文会介绍到），但一般不会使用。","","`ArrayBlockingQueue` 阻塞式获取和新增元素的方法为：","","- `put(E e)`：将元素插入队列中，如果队列已满，则该方法会一直阻塞，直到队列有空间可用或者线程被中断。","- `take()` ：获取并移除队列头部的元素，如果队列为空，则该方法会一直阻塞，直到队列非空或者线程被中断。","","这两个方法实现的关键就是在于两个条件对象 `notEmpty`(非空) 和 `notFull` （非满），这个我们在上文的构造方法中有提到。","","接下来笔者就通过两张图让大家了解一下这两个条件是如何在阻塞队列中运用的。","","![ArrayBlockingQueue 非空条件](https://oss.javaguide.cn/github/javaguide/java/collection/ArrayBlockingQueue-notEmpty-take.png)","","假设我们的代码消费者先启动，当它发现队列中没有数据，那么非空条件就会将这个线程挂起，即等待条件非空时挂起。然后 CPU 执行权到达生产者，生产者发现队列中可以存放数据，于是将数据存放进去，通知此时条件非空，此时消费者就会被唤醒到队列中使用 `take` 等方法获取值了。","","![ArrayBlockingQueue 非满条件](https://oss.javaguide.cn/github/javaguide/java/collection/ArrayBlockingQueue-notFull-put.png)","","随后的执行中，生产者生产速度远远大于消费者消费速度，于是生产者将队列塞满后再次尝试将数据存入队列，发现队列已满，于是阻塞队列就将当前线程挂起，等待非满。然后消费者拿着 CPU 执行权进行消费，于是队列可以存放新数据了，发出一个非满的通知，此时挂起的生产者就会等待 CPU 执行权到来时再次尝试将数据存到队列中。","","简单了解阻塞队列的基于两个条件的交互流程之后，我们不妨看看 `put` 和 `take` 方法的源码。","","```java","public void put(E e) throws InterruptedException {","    //确保插入的元素不为null","    checkNotNull(e);","    //加锁","    final ReentrantLock lock = this.lock;","    //这里使用lockInterruptibly()方法而不是lock()方法是为了能够响应中断操作，如果在等待获取锁的过程中被打断则该方法会抛出InterruptedException异常。","    lock.lockInterruptibly();","    try {","            //如果count等数组长度则说明队列已满，当前线程将被挂起放到AQS队列中，等待队列非满时插入（非满条件）。","       //在等待期间，锁会被释放，其他线程可以继续对队列进行操作。","        while (count == items.length)","            notFull.await();","           //如果队列可以存放元素，则调用enqueue将元素入队","        enqueue(e);","    } finally {","        //释放锁","        lock.unlock();","    }","}","```","","`put`方法内部调用了 `enqueue` 方法来实现元素入队，我们继续深入查看一下 `enqueue` 方法的实现细节：","","```java","private void enqueue(E x) {","   //获取队列底层的数组","    final Object[] items = this.items;","    //将putindex位置的值设置为我们传入的x","    items[putIndex] = x;","    //更新putindex，如果putindex等于数组长度，则更新为0","    if (++putIndex == items.length)","        putIndex = 0;","    //队列长度+1","    count++;","    //通知队列非空，那些因为获取元素而阻塞的线程可以继续工作了","    notEmpty.signal();","}","```","","从源码中可以看到入队操作的逻辑就是在数组中追加一个新元素，整体执行步骤为:","","1. 获取 `ArrayBlockingQueue` 底层的数组 `items`。","2. 将元素存到 `putIndex` 位置。","3. 更新 `putIndex` 到下一个位置，如果 `putIndex` 等于队列长度，则说明 `putIndex` 已经到达数组末尾了，下一次插入则需要 0 开始。(`ArrayBlockingQueue` 用到了循环队列的思想，即从头到尾循环复用一个数组)","4. 更新 `count` 的值，表示当前队列长度+1。","5. 调用 `notEmpty.signal()` 通知队列非空，消费者可以从队列中获取值了。","","自此我们了解了 `put` 方法的流程，为了更加完整的了解 `ArrayBlockingQueue` 关于生产者-消费者模型的设计，我们继续看看阻塞获取队列元素的 `take` 方法。","","```java","public E take() throws InterruptedException {","       //获取锁","     final ReentrantLock lock = this.lock;","     lock.lockInterruptibly();","     try {","             //如果队列中元素个数为0，则将当前线程打断并存入AQS队列中，等待队列非空时获取并移除元素（非空条件）","         while (count == 0)","             notEmpty.await();","            //如果队列不为空则调用dequeue获取元素","         return dequeue();","     } finally {","          //释放锁","         lock.unlock();","     }","}","```","","理解了 `put` 方法再看`take` 方法就很简单了，其核心逻辑和`put` 方法正好是相反的，比如`put` 方法在队列满的时候等待队列非满时插入元素（非满条件），而`take` 方法等待队列非空时获取并移除元素（非空条件）。","","`take`方法内部调用了 `dequeue` 方法来实现元素出队，其核心逻辑和 `enqueue` 方法也是相反的。","","```java","private E dequeue() {","  //获取阻塞队列底层的数组","  final Object[] items = this.items;","  @SuppressWarnings(\"unchecked\")","  //从队列中获取takeIndex位置的元素","  E x = (E) items[takeIndex];","  //将takeIndex置空","  items[takeIndex] = null;","  //takeIndex向后挪动，如果等于数组长度则更新为0","  if (++takeIndex == items.length)","      takeIndex = 0;","  //队列长度减1","  count--;","  if (itrs != null)","      itrs.elementDequeued();","  //通知那些被打断的线程当前队列状态非满，可以继续存放元素","  notFull.signal();","  return x;","}","```","","由于`dequeue` 方法（出队）和上面介绍的 `enqueue` 方法（入队）的步骤大致类似，这里就不重复介绍了。","","为了帮助理解，我专门画了一张图来展示 `notEmpty`(非空) 和 `notFull` （非满）这两个条件对象是如何控制 `ArrayBlockingQueue` 的存和取的。","","![ArrayBlockingQueue 非空非满](https://oss.javaguide.cn/github/javaguide/java/collection/ArrayBlockingQueue-notEmpty-notFull.png)","","- **消费者**：当消费者从队列中 `take` 或者 `poll` 等操作取出一个元素之后，就会通知队列非满，此时那些等待非满的生产者就会被唤醒等待获取 CPU 时间片进行入队操作。","- **生产者**：当生产者将元素存到队列中后，就会触发通知队列非空，此时消费者就会被唤醒等待 CPU 时间片尝试获取元素。如此往复，两个条件对象就构成一个环路，控制着多线程之间的存和取。","","### 非阻塞式获取和新增元素","","`ArrayBlockingQueue` 非阻塞式获取和新增元素的方法为：","","- `offer(E e)`：将元素插入队列尾部。如果队列已满，则该方法会直接返回 false，不会等待并阻塞线程。","- `poll()`：获取并移除队列头部的元素，如果队列为空，则该方法会直接返回 null，不会等待并阻塞线程。","- `add(E e)`：将元素插入队列尾部。如果队列已满则会抛出 `IllegalStateException` 异常，底层基于 `offer(E e)` 方法。","- `remove()`：移除队列头部的元素，如果队列为空则会抛出 `NoSuchElementException` 异常，底层基于 `poll()`。","- `peek()`：获取但不移除队列头部的元素，如果队列为空，则该方法会直接返回 null，不会等待并阻塞线程。","","先来看看 `offer` 方法，逻辑和 `put` 差不多，唯一的区别就是入队失败时不会阻塞当前线程，而是直接返回 `false`。","","```java","public boolean offer(E e) {","        //确保插入的元素不为null","        checkNotNull(e);","        //获取锁","        final ReentrantLock lock = this.lock;","        lock.lock();","        try {","             //队列已满直接返回false","            if (count == items.length)","                return false;","            else {","                //反之将元素入队并直接返回true","                enqueue(e);","                return true;","            }","        } finally {","            //释放锁","            lock.unlock();","        }","    }","```","","`poll` 方法同理，获取元素失败也是直接返回空，并不会阻塞获取元素的线程。","","```java","public E poll() {","        final ReentrantLock lock = this.lock;","        //上锁","        lock.lock();","        try {","            //如果队列为空直接返回null，反之出队返回元素值","            return (count == 0) ? null : dequeue();","        } finally {","            lock.unlock();","        }","    }","```","","`add` 方法其实就是对于 `offer` 做了一层封装，如下代码所示，可以看到 `add` 会调用没有规定时间的 `offer`，如果入队失败则直接抛异常。","","```java","public boolean add(E e) {","        return super.add(e);","    }","","","public boolean add(E e) {","        //调用offer方法如果失败直接抛出异常","        if (offer(e))","            return true;","        else","            throw new IllegalStateException(\"Queue full\");","    }","```","","`remove` 方法同理，调用 `poll`，如果返回 `null` 则说明队列没有元素，直接抛出异常。","","```java","public E remove() {","        E x = poll();","        if (x != null)","            return x;","        else","            throw new NoSuchElementException();","    }","```","","`peek()` 方法的逻辑也很简单，内部调用了 `itemAt` 方法。","","```java","public E peek() {","        //加锁","        final ReentrantLock lock = this.lock;","        lock.lock();","        try {","            //当队列为空时返回 null","            return itemAt(takeIndex);","        } finally {","            //释放锁","            lock.unlock();","        }","    }","","//返回队列中指定位置的元素","@SuppressWarnings(\"unchecked\")","final E itemAt(int i) {","    return (E) items[i];","}","```","","### 指定超时时间内阻塞式获取和新增元素","","在 `offer(E e)` 和 `poll()` 非阻塞获取和新增元素的基础上，设计者提供了带有等待时间的 `offer(E e, long timeout, TimeUnit unit)` 和 `poll(long timeout, TimeUnit unit)` ，用于在指定的超时时间内阻塞式地添加和获取元素。","","```java"," public boolean offer(E e, long timeout, TimeUnit unit)","        throws InterruptedException {","","        checkNotNull(e);","        long nanos = unit.toNanos(timeout);","        final ReentrantLock lock = this.lock;","        lock.lockInterruptibly();","        try {","        //队列已满，进入循环","            while (count == items.length) {","            //时间到了队列还是满的，则直接返回false","                if (nanos \u003c= 0)","                    return false;","                 //阻塞nanos时间，等待非满","                nanos = notFull.awaitNanos(nanos);","            }","            enqueue(e);","            return true;","        } finally {","            lock.unlock();","        }","    }","```","","可以看到，带有超时时间的 `offer` 方法在队列已满的情况下，会等待用户所传的时间段，如果规定时间内还不能存放元素则直接返回 `false`。","","```java","public E poll(long timeout, TimeUnit unit) throws InterruptedException {","        long nanos = unit.toNanos(timeout);","        final ReentrantLock lock = this.lock;","        lock.lockInterruptibly();","        try {","          //队列为空，循环等待，若时间到还是空的，则直接返回null","            while (count == 0) {","                if (nanos \u003c= 0)","                    return null;","                nanos = notEmpty.awaitNanos(nanos);","            }","            return dequeue();","        } finally {","            lock.unlock();","        }","    }","```","","同理，带有超时时间的 `poll` 也一样，队列为空则在规定时间内等待，若时间到了还是空的，则直接返回 null。","","### 判断元素是否存在","","`ArrayBlockingQueue` 提供了 `contains(Object o)` 来判断指定元素是否存在于队列中。","","```java","public boolean contains(Object o) {","    //若目标元素为空，则直接返回 false","    if (o == null) return false;","    //获取当前队列的元素数组","    final Object[] items = this.items;","    //加锁","    final ReentrantLock lock = this.lock;","    lock.lock();","    try {","        // 如果队列非空","        if (count \u003e 0) {","            final int putIndex = this.putIndex;","            //从队列头部开始遍历","            int i = takeIndex;","            do {","                if (o.equals(items[i]))","                    return true;","                if (++i == items.length)","                    i = 0;","            } while (i != putIndex);","        }","        return false;","    } finally {","        //释放锁","        lock.unlock();","    }","}","```","","## ArrayBlockingQueue 获取和新增元素的方法对比","","为了帮助理解 `ArrayBlockingQueue` ，我们再来对比一下上面提到的这些获取和新增元素的方法。","","新增元素：","","| 方法                                      | 队列满时处理方式                                         | 方法返回值 |","| ----------------------------------------- | -------------------------------------------------------- | ---------- |","| `put(E e)`                                | 线程阻塞，直到中断或被唤醒                               | void       |","| `offer(E e)`                              | 直接返回 false                                           | boolean    |","| `offer(E e, long timeout, TimeUnit unit)` | 指定超时时间内阻塞，超过规定时间还未添加成功则返回 false | boolean    |","| `add(E e)`                                | 直接抛出 `IllegalStateException` 异常                    | boolean    |","","获取/移除元素：","","| 方法                                | 队列空时处理方式                                    | 方法返回值 |","| ----------------------------------- | --------------------------------------------------- | ---------- |","| `take()`                            | 线程阻塞，直到中断或被唤醒                          | E          |","| `poll()`                            | 返回 null                                           | E          |","| `poll(long timeout, TimeUnit unit)` | 指定超时时间内阻塞，超过规定时间还是空的则返回 null | E          |","| `peek()`                            | 返回 null                                           | E          |","| `remove()`                          | 直接抛出 `NoSuchElementException` 异常              | boolean    |","","![](https://oss.javaguide.cn/github/javaguide/java/collection/ArrayBlockingQueue-get-add-element-methods.png)","","## ArrayBlockingQueue 相关面试题","","### ArrayBlockingQueue 是什么？它的特点是什么？","","`ArrayBlockingQueue` 是 `BlockingQueue` 接口的有界队列实现类，常用于多线程之间的数据共享，底层采用数组实现，从其名字就能看出来了。","","`ArrayBlockingQueue` 的容量有限，一旦创建，容量不能改变。","","为了保证线程安全，`ArrayBlockingQueue` 的并发控制采用可重入锁 `ReentrantLock` ，不管是插入操作还是读取操作，都需要获取到锁才能进行操作。并且，它还支持公平和非公平两种方式的锁访问机制，默认是非公平锁。","","`ArrayBlockingQueue` 虽名为阻塞队列，但也支持非阻塞获取和新增元素（例如 `poll()` 和 `offer(E e)` 方法），只是队列满时添加元素会抛出异常，队列为空时获取的元素为 null，一般不会使用。","","### ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别？","","`ArrayBlockingQueue` 和 `LinkedBlockingQueue` 是 Java 并发包中常用的两种阻塞队列实现，它们都是线程安全的。不过，不过它们之间也存在下面这些区别：","","- 底层实现：`ArrayBlockingQueue` 基于数组实现，而 `LinkedBlockingQueue` 基于链表实现。","- 是否有界：`ArrayBlockingQueue` 是有界队列，必须在创建时指定容量大小。`LinkedBlockingQueue` 创建时可以不指定容量大小，默认是`Integer.MAX_VALUE`，也就是无界的。但也可以指定队列大小，从而成为有界的。","- 锁是否分离： `ArrayBlockingQueue`中的锁是没有分离的，即生产和消费用的是同一个锁；`LinkedBlockingQueue`中的锁是分离的，即生产用的是`putLock`，消费是`takeLock`，这样可以防止生产者和消费者线程之间的锁争夺。","- 内存占用：`ArrayBlockingQueue` 需要提前分配数组内存，而 `LinkedBlockingQueue` 则是动态分配链表节点内存。这意味着，`ArrayBlockingQueue` 在创建时就会占用一定的内存空间，且往往申请的内存比实际所用的内存更大，而`LinkedBlockingQueue` 则是根据元素的增加而逐渐占用内存空间。","","### ArrayBlockingQueue 和 ConcurrentLinkedQueue 有什么区别？","","`ArrayBlockingQueue` 和 `ConcurrentLinkedQueue` 是 Java 并发包中常用的两种队列实现，它们都是线程安全的。不过，不过它们之间也存在下面这些区别：","","- 底层实现：`ArrayBlockingQueue` 基于数组实现，而 `ConcurrentLinkedQueue` 基于链表实现。","- 是否有界：`ArrayBlockingQueue` 是有界队列，必须在创建时指定容量大小，而 `ConcurrentLinkedQueue` 是无界队列，可以动态地增加容量。","- 是否阻塞：`ArrayBlockingQueue` 支持阻塞和非阻塞两种获取和新增元素的方式（一般只会使用前者）， `ConcurrentLinkedQueue` 是无界的，仅支持非阻塞式获取和新增元素。","","### ArrayBlockingQueue 的实现原理是什么？","","`ArrayBlockingQueue` 的实现原理主要分为以下几点（这里以阻塞式获取和新增元素为例介绍）：","","- `ArrayBlockingQueue` 内部维护一个定长的数组用于存储元素。","- 通过使用 `ReentrantLock` 锁对象对读写操作进行同步，即通过锁机制来实现线程安全。","- 通过 `Condition` 实现线程间的等待和唤醒操作。","","这里再详细介绍一下线程间的等待和唤醒具体的实现（不需要记具体的方法，面试中回答要点即可）：","","- 当队列已满时，生产者线程会调用 `notFull.await()` 方法让生产者进行等待，等待队列非满时插入（非满条件）。","- 当队列为空时，消费者线程会调用 `notEmpty.await()`方法让消费者进行等待，等待队列非空时消费（非空条件）。","- 当有新的元素被添加时，生产者线程会调用 `notEmpty.signal()`方法唤醒正在等待消费的消费者线程。","- 当队列中有元素被取出时，消费者线程会调用 `notFull.signal()`方法唤醒正在等待插入元素的生产者线程。","","关于 `Condition`接口的补充：","","\u003e `Condition`是 JDK1.5 之后才有的，它具有很好的灵活性，比如可以实现多路通知功能也就是在一个`Lock`对象中可以创建多个`Condition`实例（即对象监视器），**线程对象可以注册在指定的`Condition`中，从而可以有选择性的进行线程通知，在调度线程上更加灵活。 在使用`notify()/notifyAll()`方法进行通知时，被通知的线程是由 JVM 选择的，用`ReentrantLock`类结合`Condition`实例可以实现“选择性通知”** ，这个功能非常重要，而且是 `Condition` 接口默认提供的。而`synchronized`关键字就相当于整个 `Lock` 对象中只有一个`Condition`实例，所有的线程都注册在它一个身上。如果执行`notifyAll()`方法的话就会通知所有处于等待状态的线程，这样会造成很大的效率问题。而`Condition`实例的`signalAll()`方法，只会唤醒注册在该`Condition`实例中的所有等待线程。","","## 参考文献","","- 深入理解 Java 系列 | BlockingQueue 用法详解：\u003chttps://juejin.cn/post/6999798721269465102\u003e","- 深入浅出阻塞队列 BlockingQueue 及其典型实现 ArrayBlockingQueue：\u003chttps://zhuanlan.zhihu.com/p/539619957\u003e","- 并发编程大扫盲：ArrayBlockingQueue 底层原理和实战：\u003chttps://zhuanlan.zhihu.com/p/339662987\u003e","\u003c!-- @include: @article-footer.snippet.md --\u003e"],"stylingDirectives":[[[0,3,"pl-s"]],[[0,5,"pl-ent"],[7,30,"pl-s"]],[[0,8,"pl-ent"],[10,14,"pl-s"]],[[0,3,"pl-ent"]],[[4,10,"pl-s"]],[[0,3,"pl-s"]],[],[[0,9,"pl-mh"],[3,9,"pl-en"]],[],[[0,11,"pl-mh"],[4,11,"pl-en"]],[],[[42,43,"pl-s"],[43,63,"pl-c1"],[63,64,"pl-s"]],[],[[37,38,"pl-s"],[38,56,"pl-c1"],[56,57,"pl-s"],[60,61,"pl-s"],[61,80,"pl-c1"],[80,81,"pl-s"],[107,108,"pl-s"],[108,126,"pl-c1"],[126,127,"pl-s"],[165,166,"pl-s"],[166,185,"pl-c1"],[185,186,"pl-s"],[210,211,"pl-s"],[211,230,"pl-c1"],[230,231,"pl-s"],[243,244,"pl-s"],[244,262,"pl-c1"],[262,263,"pl-s"],[277,278,"pl-s"],[278,297,"pl-c1"],[297,298,"pl-s"],[347,348,"pl-s"],[348,365,"pl-c1"],[365,366,"pl-s"]],[],[],[],[[0,1,"pl-s"],[1,2,"pl-v"],[16,17,"pl-s"],[17,33,"pl-c1"],[33,34,"pl-s"]],[[0,1,"pl-s"],[1,2,"pl-v"],[16,17,"pl-s"],[17,30,"pl-c1"],[30,31,"pl-s"]],[[0,1,"pl-s"],[1,2,"pl-v"],[16,17,"pl-s"],[17,27,"pl-c1"],[27,28,"pl-s"]],[],[[0,11,"pl-mh"],[4,11,"pl-en"]],[],[],[],[[0,1,"pl-s"],[1,2,"pl-v"]],[[0,1,"pl-s"],[1,2,"pl-v"]],[[0,1,"pl-s"],[1,2,"pl-v"]],[[0,1,"pl-s"],[1,2,"pl-v"]],[],[[96,97,"pl-s"],[97,100,"pl-c1"],[100,101,"pl-s"],[102,103,"pl-s"],[103,107,"pl-c1"],[107,108,"pl-s"],[109,110,"pl-s"],[110,116,"pl-c1"],[116,117,"pl-s"],[118,119,"pl-s"],[119,123,"pl-c1"],[123,124,"pl-s"]],[],[[73,74,"pl-s"],[74,83,"pl-c1"],[83,84,"pl-s"]],[],[[0,3,"pl-s"],[3,7,"pl-en"]],[[0,6,"pl-k"],[26,29,"pl-k"]],[[28,31,"pl-k"]],[[28,32,"pl-k"]],[[28,36,"pl-smi"]],[[28,51,"pl-k"],[42,50,"pl-smi"]],[[28,41,"pl-smi"]],[[28,52,"pl-smi"],[63,70,"pl-c"],[63,65,"pl-c"]],[],[],[[3,21,"pl-smi"]],[],[[40,58,"pl-smi"],[73,91,"pl-smi"],[111,129,"pl-smi"]],[],[[52,54,"pl-c1"],[82,83,"pl-c1"]],[[68,70,"pl-c1"],[109,111,"pl-c1"],[122,124,"pl-c1"]],[],[],[[0,6,"pl-k"],[7,12,"pl-k"],[13,36,"pl-en"]],[],[[4,10,"pl-k"],[11,17,"pl-k"],[18,22,"pl-k"],[23,27,"pl-en"],[28,34,"pl-k"],[37,41,"pl-v"],[43,49,"pl-k"],[50,70,"pl-smi"]],[],[[8,41,"pl-c"],[8,10,"pl-c"]],[[8,35,"pl-k"],[27,34,"pl-smi"],[42,43,"pl-k"],[44,47,"pl-k"],[48,68,"pl-k"],[69,70,"pl-c1"]],[],[[8,18,"pl-c"],[8,10,"pl-c"]],[[8,14,"pl-smi"],[24,25,"pl-k"],[26,29,"pl-k"],[30,36,"pl-smi"],[40,41,"pl-k"],[41,42,"pl-k"]],[[12,15,"pl-k"]],[[16,19,"pl-k"],[21,24,"pl-k"],[27,28,"pl-k"],[29,30,"pl-c1"],[34,36,"pl-k"],[37,39,"pl-c1"],[42,44,"pl-k"]],[[20,43,"pl-c"],[20,22,"pl-c"]],[[25,26,"pl-k"]],[[20,26,"pl-smi"],[26,27,"pl-k"],[30,31,"pl-k"],[39,49,"pl-s"],[39,40,"pl-pds"],[48,49,"pl-pds"],[50,51,"pl-k"]],[],[[14,19,"pl-k"],[21,41,"pl-smi"]],[[17,18,"pl-k"]],[],[],[],[],[[8,22,"pl-smi"],[38,39,"pl-k"],[40,43,"pl-k"],[44,58,"pl-smi"],[59,60,"pl-c1"]],[],[[8,18,"pl-c"],[8,10,"pl-c"]],[[8,14,"pl-smi"],[24,25,"pl-k"],[26,29,"pl-k"],[30,36,"pl-smi"],[40,41,"pl-k"],[41,42,"pl-k"]],[[12,15,"pl-k"]],[[16,19,"pl-k"],[26,27,"pl-k"],[28,29,"pl-c1"]],[[16,21,"pl-k"],[23,27,"pl-c1"]],[],[[20,43,"pl-c"],[20,22,"pl-c"]],[[20,23,"pl-k"],[32,33,"pl-k"],[39,40,"pl-k"]],[[20,26,"pl-smi"],[26,27,"pl-k"],[30,31,"pl-k"],[39,49,"pl-s"],[39,40,"pl-pds"],[48,49,"pl-pds"],[50,51,"pl-k"]],[[20,22,"pl-k"]],[[20,22,"pl-k"],[30,32,"pl-k"],[33,35,"pl-c1"]],[[24,29,"pl-k"]],[],[],[],[[30,31,"pl-k"]],[[14,19,"pl-k"],[21,41,"pl-smi"]],[[17,18,"pl-k"]],[],[],[],[],[[8,15,"pl-c"],[8,10,"pl-c"]],[[16,17,"pl-k"]],[[16,17,"pl-k"]],[],[[8,17,"pl-c"],[8,10,"pl-c"]],[[16,17,"pl-k"]],[[16,17,"pl-k"]],[],[[22,23,"pl-k"]],[],[[16,17,"pl-k"]],[[16,17,"pl-k"]],[],[],[],[],[],[],[],[],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,10,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,9,"pl-c1"]],[[8,10,"pl-c1"]],[],[],[],[],[[16,17,"pl-c1"],[45,46,"pl-c1"],[71,72,"pl-c1"]],[],[],[[0,6,"pl-k"],[7,12,"pl-k"],[13,29,"pl-en"]],[],[[4,10,"pl-k"],[11,17,"pl-k"],[18,22,"pl-k"],[23,27,"pl-en"],[28,34,"pl-k"],[37,41,"pl-v"]],[[8,41,"pl-c"],[8,10,"pl-c"]],[[8,34,"pl-k"],[27,33,"pl-smi"],[41,42,"pl-k"],[43,46,"pl-k"],[47,67,"pl-k"],[68,69,"pl-c1"]],[],[[8,19,"pl-c"],[8,10,"pl-c"]],[[8,14,"pl-smi"],[14,15,"pl-k"],[18,19,"pl-k"],[32,33,"pl-k"],[39,42,"pl-s"],[39,40,"pl-pds"],[41,42,"pl-pds"]],[[8,14,"pl-smi"],[14,15,"pl-k"],[18,19,"pl-k"],[32,33,"pl-k"],[39,42,"pl-s"],[39,40,"pl-pds"],[41,42,"pl-pds"]],[[8,14,"pl-smi"],[14,15,"pl-k"],[18,19,"pl-k"],[32,33,"pl-k"],[39,42,"pl-s"],[39,40,"pl-pds"],[41,42,"pl-pds"]],[],[[8,36,"pl-c"],[8,10,"pl-c"]],[[8,14,"pl-smi"],[14,15,"pl-k"],[18,19,"pl-k"],[32,33,"pl-k"],[39,42,"pl-s"],[39,40,"pl-pds"],[41,42,"pl-pds"]],[],[[8,19,"pl-c"],[8,10,"pl-c"]],[[8,14,"pl-smi"],[14,15,"pl-k"],[18,19,"pl-k"],[32,33,"pl-k"]],[[8,14,"pl-smi"],[14,15,"pl-k"],[18,19,"pl-k"],[32,33,"pl-k"]],[[8,14,"pl-smi"],[14,15,"pl-k"],[18,19,"pl-k"],[32,33,"pl-k"]],[],[[8,35,"pl-c"],[8,10,"pl-c"]],[[8,14,"pl-smi"],[14,15,"pl-k"],[18,19,"pl-k"],[32,33,"pl-k"]],[],[],[],[],[],[[25,26,"pl-c1"],[35,36,"pl-c1"],[48,52,"pl-c1"],[55,56,"pl-c1"],[78,83,"pl-c1"],[110,111,"pl-c1"]],[],[],[[0,4,"pl-c1"]],[[0,4,"pl-c1"]],[[0,4,"pl-c1"]],[[0,5,"pl-c1"]],[[0,1,"pl-smi"]],[[0,1,"pl-smi"]],[[0,1,"pl-smi"]],[[0,4,"pl-c1"]],[],[],[[196,197,"pl-c1"]],[],[],[[0,6,"pl-k"],[7,12,"pl-k"],[13,27,"pl-en"]],[],[[4,10,"pl-k"],[11,17,"pl-k"],[18,22,"pl-k"],[23,27,"pl-en"],[28,34,"pl-k"],[37,41,"pl-v"]],[[8,41,"pl-c"],[8,10,"pl-c"]],[[8,35,"pl-k"],[27,34,"pl-smi"],[42,43,"pl-k"],[44,47,"pl-k"],[48,68,"pl-k"],[69,70,"pl-c1"]],[],[[8,19,"pl-c"],[8,10,"pl-c"]],[[13,14,"pl-k"],[18,19,"pl-c1"]],[[13,14,"pl-k"],[18,19,"pl-c1"]],[[13,14,"pl-k"],[18,19,"pl-c1"]],[[13,14,"pl-k"],[18,19,"pl-c1"]],[[13,14,"pl-k"],[18,19,"pl-c1"]],[],[[8,34,"pl-c"],[8,10,"pl-c"]],[[8,21,"pl-k"],[13,20,"pl-smi"],[27,28,"pl-k"],[29,32,"pl-k"],[33,44,"pl-k"]],[],[[8,33,"pl-c"],[8,10,"pl-c"]],[[13,14,"pl-k"]],[],[[8,23,"pl-c"],[8,10,"pl-c"]],[[8,14,"pl-smi"],[14,15,"pl-k"],[18,19,"pl-k"]],[],[],[],[],[],[],[],[],[[1,2,"pl-c1"],[4,5,"pl-c1"],[7,8,"pl-c1"],[10,11,"pl-c1"],[13,14,"pl-c1"]],[],[],[[3,21,"pl-smi"]],[],[[37,55,"pl-smi"]],[],[],[],[[5,23,"pl-smi"],[41,59,"pl-smi"]],[],[[0,1,"pl-k"],[2,20,"pl-smi"],[30,31,"pl-k"],[31,120,"pl-c"],[31,33,"pl-c"]],[],[[11,29,"pl-smi"],[40,53,"pl-smi"],[70,83,"pl-smi"],[93,111,"pl-smi"]],[],[[5,23,"pl-smi"],[31,44,"pl-smi"],[59,77,"pl-smi"],[82,87,"pl-smi"],[122,140,"pl-smi"]],[],[[23,36,"pl-smi"],[71,89,"pl-smi"],[97,110,"pl-smi"],[138,151,"pl-smi"],[166,184,"pl-smi"]],[],[[29,42,"pl-smi"],[65,83,"pl-smi"],[104,109,"pl-smi"]],[],[],[[0,6,"pl-k"],[7,15,"pl-k"],[16,21,"pl-k"],[22,35,"pl-en"]],[[4,11,"pl-k"],[12,33,"pl-e"],[31,32,"pl-smi"]],[[4,14,"pl-k"],[15,23,"pl-e"],[21,22,"pl-smi"]],[[7,12,"pl-c"],[7,9,"pl-c"]],[],[],[],[[46,64,"pl-smi"],[84,85,"pl-k"]],[],[[0,2,"pl-c1"],[9,14,"pl-smi"],[51,55,"pl-c1"]],[[0,2,"pl-c1"]],[],[],[[0,6,"pl-k"],[7,14,"pl-k"],[19,20,"pl-smi"]],[[2,4,"pl-k"]],[[6,12,"pl-k"],[13,17,"pl-c1"]],[[2,6,"pl-k"]],[[6,11,"pl-k"],[12,15,"pl-k"],[16,37,"pl-smi"],[38,50,"pl-s"],[38,39,"pl-pds"],[49,50,"pl-pds"]],[],[],[],[[3,16,"pl-smi"],[25,30,"pl-smi"],[97,115,"pl-smi"]],[],[[12,25,"pl-smi"],[43,61,"pl-smi"],[76,89,"pl-smi"]],[],[[4,17,"pl-smi"],[39,44,"pl-smi"]],[],[],[[0,6,"pl-k"],[7,16,"pl-k"],[17,30,"pl-en"],[34,41,"pl-k"],[42,50,"pl-e"],[48,49,"pl-smi"]],[],[[5,49,"pl-c"],[5,7,"pl-c"]],[[4,11,"pl-k"],[12,15,"pl-en"],[16,17,"pl-smi"],[18,19,"pl-v"]],[],[[5,29,"pl-c"],[5,7,"pl-c"]],[[4,11,"pl-k"],[12,17,"pl-en"],[18,19,"pl-smi"],[20,21,"pl-v"]],[],[[5,82,"pl-c"],[5,7,"pl-c"]],[[4,8,"pl-k"],[9,12,"pl-en"],[13,14,"pl-smi"],[15,16,"pl-v"],[18,24,"pl-k"],[25,45,"pl-smi"]],[],[[3,72,"pl-c"],[3,5,"pl-c"]],[[4,11,"pl-k"],[12,17,"pl-en"],[18,19,"pl-smi"],[20,21,"pl-v"],[23,27,"pl-k"],[28,35,"pl-v"],[37,45,"pl-smi"],[46,50,"pl-v"]],[[8,14,"pl-k"],[15,35,"pl-smi"]],[],[[4,78,"pl-c"],[4,6,"pl-c"]],[[4,5,"pl-smi"],[6,10,"pl-en"],[13,19,"pl-k"],[20,40,"pl-smi"]],[],[[6,72,"pl-c"],[6,8,"pl-c"]],[[4,5,"pl-smi"],[6,10,"pl-en"],[11,15,"pl-k"],[16,23,"pl-v"],[25,33,"pl-smi"],[34,38,"pl-v"]],[[8,14,"pl-k"],[15,35,"pl-smi"]],[],[[6,18,"pl-c"],[6,8,"pl-c"]],[[4,7,"pl-k"],[8,25,"pl-en"]],[],[[5,38,"pl-c"],[5,7,"pl-c"]],[[4,11,"pl-k"],[12,18,"pl-en"],[19,25,"pl-smi"],[26,27,"pl-v"]],[],[[4,19,"pl-c"],[4,6,"pl-c"]],[[4,10,"pl-k"],[11,18,"pl-k"],[19,27,"pl-en"],[28,34,"pl-smi"],[35,36,"pl-v"]],[],[[5,24,"pl-c"],[5,7,"pl-c"]],[[4,7,"pl-k"],[8,15,"pl-en"],[16,37,"pl-k"],[35,36,"pl-smi"],[38,39,"pl-v"]],[],[[4,26,"pl-c"],[4,6,"pl-c"]],[[4,7,"pl-k"],[8,15,"pl-en"],[16,37,"pl-k"],[35,36,"pl-smi"],[38,39,"pl-v"],[41,44,"pl-k"],[45,56,"pl-v"]],[],[],[],[[5,18,"pl-smi"],[35,53,"pl-smi"],[61,74,"pl-smi"],[89,102,"pl-smi"],[122,135,"pl-smi"]],[],[],[[0,6,"pl-k"],[7,14,"pl-k"],[19,20,"pl-smi"]],[[2,73,"pl-c"],[2,4,"pl-c"]],[[2,4,"pl-k"]],[[6,12,"pl-k"],[13,17,"pl-c1"]],[[2,6,"pl-k"]],[[6,11,"pl-k"],[12,15,"pl-k"],[16,37,"pl-smi"],[38,50,"pl-s"],[38,39,"pl-pds"],[49,50,"pl-pds"]],[],[],[],[],[],[[4,22,"pl-smi"],[65,83,"pl-smi"],[87,88,"pl-c1"]],[],[],[[0,34,"pl-c"],[0,2,"pl-c"]],[[0,6,"pl-k"],[26,29,"pl-k"],[40,47,"pl-k"]],[[2,46,"pl-c"],[2,4,"pl-c"]],[[2,4,"pl-k"],[15,17,"pl-k"],[18,19,"pl-c1"]],[[6,11,"pl-k"],[12,15,"pl-k"],[16,40,"pl-smi"]],[[2,20,"pl-c"],[2,4,"pl-c"]],[[2,6,"pl-c1"],[6,7,"pl-k"],[13,14,"pl-k"],[15,18,"pl-k"],[19,25,"pl-smi"]],[[2,16,"pl-c"],[2,4,"pl-c"]],[[7,8,"pl-k"],[9,12,"pl-k"],[13,26,"pl-smi"]],[[2,25,"pl-c"],[2,4,"pl-c"]],[[11,12,"pl-k"],[17,18,"pl-k"]],[[10,11,"pl-k"],[17,18,"pl-k"]],[],[],[],[],[],[[51,69,"pl-smi"]],[],[],[[1,7,"pl-k"],[27,30,"pl-k"]],[[8,12,"pl-c1"],[23,28,"pl-c1"]],[],[],[],[[40,50,"pl-smi"]],[],[],[[0,6,"pl-k"],[26,29,"pl-k"],[40,47,"pl-k"]],[[30,53,"pl-k"],[51,52,"pl-smi"]],[[2,15,"pl-c"],[2,4,"pl-c"]],[[2,6,"pl-c1"]],[],[[2,7,"pl-k"],[8,21,"pl-smi"],[27,28,"pl-k"],[29,33,"pl-c1"],[33,34,"pl-k"]],[[2,40,"pl-c"],[2,4,"pl-c"]],[[6,7,"pl-k"]],[[2,5,"pl-k"]],[[6,9,"pl-k"],[12,13,"pl-k"],[14,15,"pl-c1"]],[[6,9,"pl-k"]],[[16,29,"pl-c"],[16,18,"pl-c"]],[[10,13,"pl-k"],[15,16,"pl-smi"],[19,20,"pl-k"]],[],[[21,23,"pl-k"],[25,26,"pl-k"]],[],[[8,13,"pl-k"],[15,45,"pl-smi"]],[[10,15,"pl-k"],[16,19,"pl-k"],[20,44,"pl-smi"]],[],[[6,16,"pl-c"],[6,8,"pl-c"]],[[12,13,"pl-k"]],[[22,58,"pl-c"],[22,24,"pl-c"]],[[15,16,"pl-k"],[20,22,"pl-k"],[33,34,"pl-k"],[35,36,"pl-c1"],[37,38,"pl-k"]],[[4,11,"pl-k"]],[[6,16,"pl-c"],[6,8,"pl-c"]],[[10,11,"pl-k"]],[],[],[],[],[],[],[[1,19,"pl-smi"],[39,40,"pl-k"],[85,86,"pl-smi"]],[],[[1,19,"pl-smi"]],[],[[0,1,"pl-k"],[7,8,"pl-smi"]],[[0,1,"pl-k"]],[],[],[],[],[],[[0,1,"pl-k"],[2,20,"pl-smi"],[32,33,"pl-k"],[33,122,"pl-c"],[33,35,"pl-c"]],[],[[56,59,"pl-c1"]],[],[[0,1,"pl-k"],[2,20,"pl-smi"],[32,33,"pl-k"],[33,120,"pl-c"],[33,35,"pl-c"]],[],[[84,87,"pl-c1"],[132,135,"pl-c1"]],[],[],[],[],[[0,6,"pl-k"],[7,11,"pl-k"],[16,17,"pl-smi"],[28,48,"pl-smi"]],[[4,19,"pl-c"],[4,6,"pl-c"]],[],[[4,8,"pl-c"],[4,6,"pl-c"]],[[4,9,"pl-k"],[10,23,"pl-smi"],[29,30,"pl-k"],[31,35,"pl-c1"],[35,36,"pl-k"]],[[4,99,"pl-c"],[4,6,"pl-c"]],[[8,9,"pl-k"]],[[4,7,"pl-k"]],[[12,67,"pl-c"],[12,14,"pl-c"]],[[7,37,"pl-c"],[7,9,"pl-c"]],[[8,13,"pl-k"],[21,23,"pl-k"],[29,30,"pl-k"]],[[19,20,"pl-k"]],[[11,39,"pl-c"],[11,13,"pl-c"]],[],[[6,13,"pl-k"]],[[8,13,"pl-c"],[8,10,"pl-c"]],[[12,13,"pl-k"]],[],[],[],[],[],[],[],[[0,7,"pl-k"],[8,12,"pl-k"],[21,22,"pl-smi"]],[[3,14,"pl-c"],[3,5,"pl-c"]],[[4,9,"pl-k"],[10,16,"pl-k"],[25,26,"pl-k"],[27,31,"pl-c1"],[31,32,"pl-k"]],[[4,28,"pl-c"],[4,6,"pl-c"]],[[20,21,"pl-k"]],[[4,39,"pl-c"],[4,6,"pl-c"]],[[4,6,"pl-k"],[8,10,"pl-k"],[19,21,"pl-k"],[27,28,"pl-k"]],[[17,18,"pl-k"],[19,20,"pl-c1"]],[[4,12,"pl-c"],[4,6,"pl-c"]],[[9,11,"pl-k"]],[[4,34,"pl-c"],[4,6,"pl-c"]],[[12,13,"pl-k"]],[],[],[],[[36,37,"pl-k"]],[],[[0,2,"pl-c1"],[7,25,"pl-smi"]],[[0,2,"pl-c1"]],[[0,2,"pl-c1"],[79,80,"pl-c1"],[86,104,"pl-smi"]],[[0,2,"pl-c1"],[25,26,"pl-k"],[26,27,"pl-c1"]],[[0,2,"pl-c1"],[15,16,"pl-k"]],[],[[31,49,"pl-smi"],[56,57,"pl-k"]],[],[],[[0,6,"pl-k"],[7,8,"pl-smi"],[23,43,"pl-smi"]],[[7,12,"pl-c"],[7,9,"pl-c"]],[[5,10,"pl-k"],[11,24,"pl-smi"],[30,31,"pl-k"],[32,36,"pl-c1"],[36,37,"pl-k"]],[[9,10,"pl-k"]],[[5,8,"pl-k"]],[[13,65,"pl-c"],[13,15,"pl-c"]],[[9,14,"pl-k"],[22,24,"pl-k"],[25,26,"pl-c1"]],[[21,22,"pl-k"]],[[12,35,"pl-c"],[12,14,"pl-c"]],[[9,15,"pl-k"]],[[7,14,"pl-k"]],[[10,15,"pl-c"],[10,12,"pl-c"]],[[13,14,"pl-k"]],[],[],[],[],[],[],[],[],[],[[0,7,"pl-k"],[8,9,"pl-smi"]],[[2,15,"pl-c"],[2,4,"pl-c"]],[[2,7,"pl-k"],[8,14,"pl-k"],[23,24,"pl-k"],[25,29,"pl-c1"],[29,30,"pl-k"]],[[2,19,"pl-k"],[20,31,"pl-s"],[20,21,"pl-pds"],[30,31,"pl-pds"]],[[2,24,"pl-c"],[2,4,"pl-c"]],[[2,3,"pl-smi"],[6,7,"pl-k"],[9,10,"pl-smi"]],[[2,16,"pl-c"],[2,4,"pl-c"]],[[19,20,"pl-k"],[21,25,"pl-c1"]],[[2,31,"pl-c"],[2,4,"pl-c"]],[[2,4,"pl-k"],[6,8,"pl-k"],[18,20,"pl-k"],[26,27,"pl-k"]],[[16,17,"pl-k"],[18,19,"pl-c1"]],[[2,10,"pl-c"],[2,4,"pl-c"]],[[7,9,"pl-k"]],[[2,4,"pl-k"],[11,13,"pl-k"],[14,18,"pl-c1"]],[[10,11,"pl-k"]],[[2,31,"pl-c"],[2,4,"pl-c"]],[[9,10,"pl-k"]],[[2,8,"pl-k"]],[],[],[],[],[],[[64,82,"pl-smi"]],[],[[0,1,"pl-k"],[2,20,"pl-smi"],[32,33,"pl-k"],[33,125,"pl-c"],[33,35,"pl-c"]],[],[[0,1,"pl-k"],[2,4,"pl-k"],[7,9,"pl-k"],[79,82,"pl-c1"]],[[0,1,"pl-k"],[2,4,"pl-k"],[7,9,"pl-k"],[48,51,"pl-c1"]],[],[],[],[[1,19,"pl-smi"]],[],[[0,1,"pl-k"],[9,10,"pl-smi"],[42,47,"pl-c1"]],[[0,1,"pl-k"],[41,45,"pl-c1"]],[[0,1,"pl-k"],[7,8,"pl-smi"],[35,56,"pl-smi"],[73,74,"pl-smi"]],[[0,1,"pl-k"],[35,57,"pl-smi"]],[[0,1,"pl-k"],[42,46,"pl-c1"]],[],[[59,64,"pl-c1"]],[],[],[[0,6,"pl-k"],[7,14,"pl-k"],[21,22,"pl-smi"]],[[8,23,"pl-c"],[8,10,"pl-c"]],[],[[8,13,"pl-c"],[8,10,"pl-c"]],[[8,13,"pl-k"],[14,27,"pl-smi"],[33,34,"pl-k"],[35,39,"pl-c1"],[39,40,"pl-k"]],[[12,13,"pl-k"]],[[8,11,"pl-k"]],[[13,28,"pl-c"],[13,15,"pl-c"]],[[12,14,"pl-k"],[22,24,"pl-k"],[30,31,"pl-k"]],[[16,22,"pl-k"],[23,28,"pl-c1"]],[[12,16,"pl-k"]],[[16,34,"pl-c"],[16,18,"pl-c"]],[],[[16,22,"pl-k"],[23,27,"pl-c1"]],[],[[10,17,"pl-k"]],[[12,17,"pl-c"],[12,14,"pl-c"]],[[16,17,"pl-k"]],[],[],[],[],[],[],[],[[0,6,"pl-k"],[7,8,"pl-smi"]],[[8,13,"pl-k"],[14,27,"pl-smi"],[33,34,"pl-k"],[35,39,"pl-c1"],[39,40,"pl-k"]],[[8,12,"pl-c"],[8,10,"pl-c"]],[[12,13,"pl-k"]],[[8,11,"pl-k"]],[[12,38,"pl-c"],[12,14,"pl-c"]],[[12,18,"pl-k"],[26,28,"pl-k"],[29,30,"pl-c1"],[32,33,"pl-k"],[34,38,"pl-c1"],[39,40,"pl-k"]],[[10,17,"pl-k"]],[[16,17,"pl-k"]],[],[],[],[],[],[],[],[[0,6,"pl-k"],[7,14,"pl-k"],[19,20,"pl-smi"]],[[8,14,"pl-k"],[15,20,"pl-c1"],[20,21,"pl-k"]],[],[],[],[[0,6,"pl-k"],[7,14,"pl-k"],[19,20,"pl-smi"]],[[8,29,"pl-c"],[8,10,"pl-c"]],[[8,10,"pl-k"]],[[12,18,"pl-k"],[19,23,"pl-c1"]],[[8,12,"pl-k"]],[[12,17,"pl-k"],[18,21,"pl-k"],[22,43,"pl-smi"],[44,56,"pl-s"],[44,45,"pl-pds"],[55,56,"pl-pds"]],[],[],[],[[30,34,"pl-c1"]],[],[],[[0,6,"pl-k"],[7,8,"pl-smi"]],[[8,9,"pl-smi"],[12,13,"pl-k"]],[[8,10,"pl-k"],[14,16,"pl-k"],[17,21,"pl-c1"]],[[12,18,"pl-k"]],[[8,12,"pl-k"]],[[12,17,"pl-k"],[18,21,"pl-k"],[22,44,"pl-smi"]],[],[],[],[],[],[],[[0,6,"pl-k"],[7,8,"pl-smi"]],[[8,12,"pl-c"],[8,10,"pl-c"]],[[8,13,"pl-k"],[14,27,"pl-smi"],[33,34,"pl-k"],[35,39,"pl-c1"],[39,40,"pl-k"]],[[12,13,"pl-k"]],[[8,11,"pl-k"]],[[12,27,"pl-c"],[12,14,"pl-c"]],[[12,18,"pl-k"]],[[10,17,"pl-k"]],[[12,17,"pl-c"],[12,14,"pl-c"]],[[16,17,"pl-k"]],[],[],[],[[0,14,"pl-c"],[0,2,"pl-c"]],[[0,17,"pl-k"],[18,29,"pl-s"],[18,19,"pl-pds"],[28,29,"pl-pds"]],[[0,5,"pl-k"],[6,7,"pl-smi"],[15,18,"pl-k"]],[[4,10,"pl-k"],[12,13,"pl-smi"]],[],[],[],[],[],[[9,10,"pl-smi"],[62,63,"pl-smi"],[67,71,"pl-k"],[81,89,"pl-smi"],[105,109,"pl-k"],[119,127,"pl-smi"]],[],[],[[1,7,"pl-k"],[8,15,"pl-k"],[22,23,"pl-smi"],[27,31,"pl-k"],[41,49,"pl-smi"]],[[15,35,"pl-smi"]],[],[],[[8,12,"pl-k"],[19,20,"pl-k"],[25,26,"pl-k"]],[[8,13,"pl-k"],[14,27,"pl-smi"],[33,34,"pl-k"],[35,39,"pl-c1"],[39,40,"pl-k"]],[[12,13,"pl-k"]],[[8,11,"pl-k"]],[[8,19,"pl-c"],[8,10,"pl-c"]],[[12,17,"pl-k"],[25,27,"pl-k"],[33,34,"pl-k"]],[[12,35,"pl-c"],[12,14,"pl-c"]],[[16,18,"pl-k"],[26,28,"pl-k"],[29,30,"pl-c1"]],[[20,26,"pl-k"],[27,32,"pl-c1"]],[[17,33,"pl-c"],[17,19,"pl-c"]],[[22,23,"pl-k"],[31,32,"pl-k"]],[],[],[[12,18,"pl-k"],[19,23,"pl-c1"]],[[10,17,"pl-k"]],[[16,17,"pl-k"]],[],[],[],[],[[66,71,"pl-c1"]],[],[],[[0,6,"pl-k"],[7,8,"pl-smi"],[14,18,"pl-k"],[28,36,"pl-smi"],[50,70,"pl-smi"]],[[8,12,"pl-k"],[19,20,"pl-k"],[25,26,"pl-k"]],[[8,13,"pl-k"],[14,27,"pl-smi"],[33,34,"pl-k"],[35,39,"pl-c1"],[39,40,"pl-k"]],[[12,13,"pl-k"]],[[8,11,"pl-k"]],[[10,40,"pl-c"],[10,12,"pl-c"]],[[12,17,"pl-k"],[25,27,"pl-k"],[28,29,"pl-c1"]],[[16,18,"pl-k"],[26,28,"pl-k"],[29,30,"pl-c1"]],[[20,26,"pl-k"],[27,31,"pl-c1"]],[[22,23,"pl-k"],[32,33,"pl-k"]],[],[[12,18,"pl-k"]],[[10,17,"pl-k"]],[[16,17,"pl-k"]],[],[],[],[],[[52,56,"pl-c1"]],[],[],[],[[1,19,"pl-smi"],[35,41,"pl-smi"]],[],[],[[0,6,"pl-k"],[7,14,"pl-k"],[24,30,"pl-smi"]],[[4,25,"pl-c"],[4,6,"pl-c"]],[[4,6,"pl-k"],[10,12,"pl-k"],[13,17,"pl-c1"],[19,25,"pl-k"],[26,31,"pl-c1"]],[[4,17,"pl-c"],[4,6,"pl-c"]],[[4,9,"pl-k"],[10,16,"pl-k"],[25,26,"pl-k"],[27,31,"pl-c1"],[31,32,"pl-k"]],[[4,8,"pl-c"],[4,6,"pl-c"]],[[4,9,"pl-k"],[10,23,"pl-smi"],[29,30,"pl-k"],[31,35,"pl-c1"],[35,36,"pl-k"]],[[8,9,"pl-k"]],[[4,7,"pl-k"]],[[8,17,"pl-c"],[8,10,"pl-c"]],[[8,10,"pl-k"],[18,19,"pl-k"],[20,21,"pl-c1"]],[[12,17,"pl-k"],[18,21,"pl-k"],[31,32,"pl-k"],[33,37,"pl-c1"],[37,38,"pl-k"]],[[12,23,"pl-c"],[12,14,"pl-c"]],[[12,15,"pl-k"],[18,19,"pl-k"]],[[12,14,"pl-k"]],[[16,18,"pl-k"],[21,22,"pl-k"]],[[20,26,"pl-k"],[27,31,"pl-c1"]],[[16,18,"pl-k"],[20,22,"pl-k"],[24,26,"pl-k"],[32,33,"pl-k"]],[[22,23,"pl-k"],[24,25,"pl-c1"]],[[14,19,"pl-k"],[23,25,"pl-k"]],[],[[8,14,"pl-k"],[15,20,"pl-c1"]],[[6,13,"pl-k"]],[[8,13,"pl-c"],[8,10,"pl-c"]],[[12,13,"pl-k"]],[],[],[],[],[[3,21,"pl-smi"]],[],[[8,26,"pl-smi"]],[],[],[],[[0,1,"pl-k"],[42,43,"pl-k"],[93,94,"pl-k"],[101,102,"pl-k"]],[[0,1,"pl-k"],[2,42,"pl-k"],[42,43,"pl-k"],[44,45,"pl-k"],[46,102,"pl-k"],[103,104,"pl-k"],[105,115,"pl-k"],[116,117,"pl-k"]],[[0,1,"pl-k"],[7,8,"pl-smi"],[44,45,"pl-k"],[90,91,"pl-k"],[92,96,"pl-k"],[103,104,"pl-k"]],[[0,1,"pl-k"],[9,10,"pl-smi"],[44,45,"pl-k"],[51,56,"pl-c1"],[99,100,"pl-k"],[101,108,"pl-k"],[112,113,"pl-k"]],[[0,1,"pl-k"],[9,10,"pl-smi"],[14,18,"pl-k"],[28,36,"pl-smi"],[44,45,"pl-k"],[72,77,"pl-c1"],[78,79,"pl-k"],[80,87,"pl-k"],[91,92,"pl-k"]],[[0,1,"pl-k"],[7,8,"pl-smi"],[44,45,"pl-k"],[52,73,"pl-smi"],[97,98,"pl-k"],[99,106,"pl-k"],[110,111,"pl-k"]],[],[[2,3,"pl-k"]],[],[[0,1,"pl-k"],[36,37,"pl-k"],[82,83,"pl-k"],[90,91,"pl-k"]],[[0,1,"pl-k"],[2,36,"pl-k"],[36,37,"pl-k"],[38,39,"pl-k"],[40,90,"pl-k"],[90,91,"pl-k"],[92,93,"pl-k"],[94,104,"pl-k"],[105,106,"pl-k"]],[[0,1,"pl-k"],[38,39,"pl-k"],[79,80,"pl-k"],[81,82,"pl-smi"],[92,93,"pl-k"]],[[0,1,"pl-k"],[38,39,"pl-k"],[43,47,"pl-c1"],[90,91,"pl-k"],[92,93,"pl-smi"],[103,104,"pl-k"]],[[0,1,"pl-k"],[8,12,"pl-k"],[22,30,"pl-smi"],[38,39,"pl-k"],[64,68,"pl-c1"],[69,70,"pl-k"],[71,72,"pl-smi"],[82,83,"pl-k"]],[[0,1,"pl-k"],[38,39,"pl-k"],[43,47,"pl-c1"],[90,91,"pl-k"],[92,93,"pl-smi"],[103,104,"pl-k"]],[[0,1,"pl-k"],[38,39,"pl-k"],[46,68,"pl-smi"],[86,87,"pl-k"],[88,95,"pl-k"],[99,100,"pl-k"]],[],[[0,1,"pl-k"],[9,10,"pl-k"],[10,109,"pl-c"],[10,12,"pl-c"]],[],[[3,21,"pl-smi"]],[],[[4,22,"pl-smi"]],[],[[1,19,"pl-smi"],[24,37,"pl-smi"]],[],[[1,19,"pl-smi"]],[],[[10,28,"pl-smi"],[43,56,"pl-smi"]],[],[[1,19,"pl-smi"],[65,66,"pl-smi"],[103,107,"pl-c1"]],[],[[4,22,"pl-smi"],[25,44,"pl-smi"]],[],[[1,19,"pl-smi"],[24,43,"pl-smi"],[47,51,"pl-smi"]],[],[[0,1,"pl-k"],[8,26,"pl-smi"],[38,57,"pl-smi"]],[[0,1,"pl-k"],[8,26,"pl-smi"],[48,67,"pl-smi"],[86,93,"pl-smi"],[93,103,"pl-c1"],[93,94,"pl-k"]],[[0,1,"pl-k"],[10,28,"pl-smi"],[54,73,"pl-smi"]],[[0,1,"pl-k"],[8,26,"pl-smi"],[42,61,"pl-smi"],[82,100,"pl-smi"],[139,158,"pl-smi"]],[],[[4,22,"pl-smi"],[25,46,"pl-smi"]],[],[[1,19,"pl-smi"],[24,45,"pl-smi"],[49,53,"pl-smi"]],[],[[0,1,"pl-k"],[8,26,"pl-smi"],[38,59,"pl-smi"]],[[0,1,"pl-k"],[8,26,"pl-smi"],[50,71,"pl-smi"]],[[0,1,"pl-k"],[8,26,"pl-smi"],[61,82,"pl-smi"]],[],[[4,22,"pl-smi"]],[],[[1,19,"pl-smi"]],[],[[0,1,"pl-k"],[3,21,"pl-smi"]],[[0,1,"pl-k"],[8,21,"pl-smi"]],[[0,1,"pl-k"],[6,15,"pl-smi"]],[],[],[],[[0,1,"pl-k"],[26,27,"pl-k"]],[[0,1,"pl-k"],[27,28,"pl-k"]],[[0,1,"pl-k"],[31,32,"pl-k"]],[[0,1,"pl-k"],[31,32,"pl-k"]],[],[[4,13,"pl-smi"]],[],[[0,1,"pl-k"],[3,12,"pl-smi"],[15,19,"pl-c1"],[19,20,"pl-k"],[20,21,"pl-c1"],[57,61,"pl-smi"],[72,81,"pl-smi"],[93,95,"pl-k"],[108,117,"pl-smi"],[160,161,"pl-k"],[190,193,"pl-c1"],[200,213,"pl-smi"],[218,227,"pl-smi"],[241,243,"pl-k"],[259,268,"pl-smi"],[280,292,"pl-k"],[304,308,"pl-smi"],[318,327,"pl-smi"],[398,407,"pl-smi"],[436,445,"pl-smi"]],[],[],[],[[0,1,"pl-k"],[7,11,"pl-smi"],[15,16,"pl-k"],[17,30,"pl-smi"],[36,37,"pl-k"],[42,43,"pl-k"],[43,80,"pl-c"],[43,45,"pl-c"]],[[0,1,"pl-k"],[11,24,"pl-smi"],[32,50,"pl-smi"],[51,52,"pl-k"],[57,58,"pl-k"],[58,91,"pl-c"],[58,60,"pl-c"]],[[0,1,"pl-k"],[10,28,"pl-smi"],[37,38,"pl-k"],[43,44,"pl-k"],[44,77,"pl-c"],[44,46,"pl-c"]],[[0,1,"pl-k"],[1,2,"pl-k"],[2,4,"pl-k"],[5,13,"pl-k"],[13,14,"pl-k"],[15,23,"pl-k"],[23,24,"pl-k"],[30,31,"pl-k"],[38,39,"pl-k"],[42,44,"pl-k"],[44,45,"pl-k"]]],"colorizedLines":null}},"title":"JavaGuide/docs/java/collection/arrayblockingqueue-source-code.md at main · cht37/JavaGuide","appPayload":{},"meta":{"title":"JavaGuide/docs/java/collection/arrayblockingqueue-source-code.md at main · cht37/JavaGuide"}}</script>
  <div data-target="react-app.reactRoot"><meta name="github-code-view-meta-stats" id="github-code-view-meta-stats" data-hydrostats="publish"/> <!-- --> <a hidden="" id="code-view-repo-link" href="/cht37/JavaGuide" data-discover="true"></a> <div class="d-none"></div><div><div style="--spacing:var(--spacing-none)" class="prc-PageLayout-PageLayoutRoot--KH-d" data-component="SplitPageLayout" data-has-sidebar="true"><div class="prc-PageLayout-SidebarWrapper-kLG4B CopilotSidePanelSidebar-module__SidePanel__L3O0C CopilotSidePanelSidebar-module__HiddenSidePanel__TBRGn" style="--spacing-column:var(--spacing-none)" data-is-hidden="false" data-position="end" data-sticky="true" data-responsive-variant="fullscreen"><div class="prc-PageLayout-VerticalDivider-9QRmK prc-PageLayout-SidebarVerticalDivider-0Rl0V" data-component="PageLayout.VerticalDivider" data-variant="line" data-position="end" style="--spacing:var(--spacing-none)"><div class="prc-PageLayout-DraggableHandle-9s6B4" data-component="PageLayout.DragHandle" role="slider" aria-label="Draggable pane splitter" aria-valuemin="450" aria-valuemax="768" aria-valuenow="544" aria-valuetext="Pane width 544 pixels" tabindex="0"></div></div><div class="prc-PageLayout-Sidebar-iciWg" data-component="SplitPageLayout.Sidebar" data-resizable="true" style="--spacing:var(--spacing-normal);--pane-min-width:450px;--pane-max-width:768px;--pane-width-custom:544px;--pane-width-size:var(--pane-width-custom);--pane-width:544px"><div class="height-full" data-testid="copilot-code-view-side-panel"><div id="copilot-side-panel-content" class="height-full"></div></div></div></div><div class="prc-PageLayout-PageLayoutWrapper-2BhU2" data-width="full"><div class="prc-PageLayout-PageLayoutContent-BneH9"><div id="repos-file-tree-sidebar" class="CodeViewFileTreeLayout-module__sidebar__n_Aau" tabindex="0"><div class="prc-PageLayout-PaneWrapper-pHPop ReposFileTreePane-module__Pane__rBZpI ReposFileTreePane-module__HideTree__AYZnm ReposFileTreePane-module__HidePane__VHAVt" style="--offset-header:0px;--spacing-row:var(--spacing-none);--spacing-column:var(--spacing-none)" data-is-hidden="false" data-position="start" data-sticky="true"><div class="prc-PageLayout-HorizontalDivider-JLVqp prc-PageLayout-PaneHorizontalDivider-9tbnE" data-component="PageLayout.HorizontalDivider" data-variant-regular="none" data-variant-narrow="none" data-position="start" style="--spacing-divider:var(--spacing-none);--spacing:var(--spacing-none)"></div><div class="prc-PageLayout-Pane-AyzHK" data-component="SplitPageLayout.Pane" data-resizable="true" style="--spacing:var(--spacing-none);--pane-min-width:256px;--pane-max-width:calc(100vw - var(--pane-max-width-diff));--pane-width-size:var(--pane-width-large);--pane-width:320px"></div><div class="prc-PageLayout-VerticalDivider-9QRmK prc-PageLayout-PaneVerticalDivider-le57g" data-component="PageLayout.VerticalDivider" data-variant-narrow="none" data-variant-regular="line" data-variant-wide="line" data-position="start" style="--spacing:var(--spacing-none)"><div class="prc-PageLayout-DraggableHandle-9s6B4" data-component="PageLayout.DragHandle" role="slider" aria-label="Draggable pane splitter" aria-valuemin="256" aria-valuemax="600" aria-valuenow="320" aria-valuetext="Pane width 320 pixels" tabindex="0"></div></div></div></div><div data-component="SplitPageLayout.Content" class="prc-PageLayout-ContentWrapper-gR9eG"><div class="prc-PageLayout-Content-xWL-A" data-width="full" style="--spacing:var(--spacing-none)"><div class="SharedPageLayout-module__content__IwGAp" data-selector="repos-split-pane-content" id="repos-split-pane-content" tabindex="0"> <!-- --> <div class="container CodeViewHeader-module__Box__JkPOb"><div class="CodeViewHeader-module__StickyHeader__Qn7UN" id="StickyHeader"><div class="CodeViewHeader-module__Box_1__SbNDV"><div class="CodeViewHeader-module__Box_2__TB46f"><div class="react-code-view-header-wrap--narrow CodeViewHeader-module__Box_3__q1zUL"><div class="CodeViewHeader-module__treeToggleWrapper__RQ__9"><h2 class="use-tree-pane-module__Heading__s4QbZ prc-Heading-Heading-MtWFE" data-component="Heading"><button data-component="Button" type="button" aria-label="Expand file tree" data-testid="expand-file-tree-button-mobile" class="prc-Button-ButtonBase-9n-Xk ExpandFileTreeButton-module__Button_1__Svs95" data-loading="false" data-size="medium" data-variant="invisible"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-arrow-left" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M7.78 12.53a.75.75 0 0 1-1.06 0L2.47 8.28a.75.75 0 0 1 0-1.06l4.25-4.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L4.81 7h7.44a.75.75 0 0 1 0 1.5H4.81l2.97 2.97a.75.75 0 0 1 0 1.06Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3">Files</span></span></button><button data-component="IconButton" type="button" data-testid="expand-file-tree-button" aria-controls="repos-file-tree" class="prc-Button-ButtonBase-9n-Xk position-relative ExpandFileTreeButton-module__expandButton__hDOcv ExpandFileTreeButton-module__filesButtonBreakpoint__zEvz3 fgColor-muted prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="invisible" aria-labelledby="_R_4lla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-sidebar-collapse" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M6.823 7.823a.25.25 0 0 1 0 .354l-2.396 2.396A.25.25 0 0 1 4 10.396V5.604a.25.25 0 0 1 .427-.177Z"></path><path d="M1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25V1.75C0 .784.784 0 1.75 0ZM1.5 1.75v12.5c0 .138.112.25.25.25H9.5v-13H1.75a.25.25 0 0 0-.25.25ZM11 14.5h3.25a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25H11Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="se" data-component="Tooltip" aria-hidden="true" id="_R_4lla9lik5_">Expand file tree</span><div class="d-none"></div></h2></div><div class="react-code-view-header-mb--narrow mr-2"><button data-component="Button" type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="main branch" data-testid="anchor-button" data-icv-name="Switch branches/tags" class="prc-Button-ButtonBase-9n-Xk ref-selector-class RefSelectorAnchoredOverlay-module__RefSelectorOverlayBtn__a3WK3" data-loading="false" data-size="medium" data-variant="default" id="ref-picker-repos-header-ref-selector-wide"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3"><div class="RefSelectorAnchoredOverlay-module__RefSelectorOverlayContainer__yaf4p"><div style="max-width:125px" class="ref-selector-button-text-container RefSelectorAnchoredOverlay-module__RefSelectorBtnTextContainer__Di3rk"><span class="RefSelectorAnchoredOverlay-module__RefSelectorText__w_fmP">main</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-YNt2F prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><div class="d-none"></div></div><div class="react-code-view-header-mb--narrow CodeViewHeader-module__Box_5__MQ0hL"><div class="Breadcrumb-module__container__Vxvev Breadcrumb-module__lg__Rjz0A"><nav data-testid="breadcrumbs" aria-labelledby="repos-header-breadcrumb-heading" id="repos-header-breadcrumb" class="Breadcrumb-module__nav__rQFDj"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading" id="repos-header-breadcrumb-heading">Breadcrumbs</h2><ol class="Breadcrumb-module__list__ZH6zr"><li class="Breadcrumb-module__listItem__Ib0x_"><a class="Breadcrumb-module__repoLink__O2Nbs prc-Link-Link-9ZwDx" data-component="Link" data-testid="breadcrumbs-repo-link" href="/cht37/JavaGuide/tree/main" data-discover="true">JavaGuide</a></li><li class="Breadcrumb-module__listItem__Ib0x_"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__lg__Rjz0A" aria-hidden="true">/</span><a class="Breadcrumb-module__directoryLink__kQy_t prc-Link-Link-9ZwDx" data-component="Link" href="/cht37/JavaGuide/tree/main/docs" data-discover="true">docs</a></li><li class="Breadcrumb-module__listItem__Ib0x_"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__lg__Rjz0A" aria-hidden="true">/</span><a class="Breadcrumb-module__directoryLink__kQy_t prc-Link-Link-9ZwDx" data-component="Link" href="/cht37/JavaGuide/tree/main/docs/java" data-discover="true">java</a></li><li class="Breadcrumb-module__listItem__Ib0x_"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__lg__Rjz0A" aria-hidden="true">/</span><a class="Breadcrumb-module__directoryLink__kQy_t prc-Link-Link-9ZwDx" data-component="Link" href="/cht37/JavaGuide/tree/main/docs/java/collection" data-discover="true">collection</a></li></ol></nav><div data-testid="breadcrumbs-filename" class="Breadcrumb-module__filename__equZR"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__lg__Rjz0A" aria-hidden="true">/</span><h1 class="Breadcrumb-module__filenameHeading__MNMtw Breadcrumb-module__lg__Rjz0A prc-Heading-Heading-MtWFE" data-component="Heading" tabindex="-1" id="file-name-id">arrayblockingqueue-source-code.md</h1></div><button data-component="IconButton" type="button" class="prc-Button-ButtonBase-9n-Xk ml-2 prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_7lla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="CopyToClipboardIconButton-module__tooltip__WyiwL prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-label="Copy path" aria-hidden="true" id="_R_7lla9lik5_">Copy path</span></div></div></div><div class="react-code-view-header-element--wide"><div class="CodeViewHeader-module__Box_7___0R6c"><div class="d-flex gap-2"><div><div class="CodeViewHeader-module__FileResultsList__JDzUy"><span class="d-flex FileResultsList-module__FilesSearchBox__ivVkc TextInput-wrapper prc-components-TextInputWrapper-Hpdqi prc-components-TextInputBaseWrapper-wY-n0" data-no-trailing-action="true" data-component="TextInput" data-leading-visual="true" data-trailing-visual="true" aria-busy="false"><span class="TextInput-icon" id="_R_5ipla9lik5_" aria-hidden="true" data-component="TextInput.LeadingVisual"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-search" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M10.68 11.74a6 6 0 0 1-7.922-8.982 6 6 0 0 1 8.982 7.922l3.04 3.04a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215ZM11.5 7a4.499 4.499 0 1 0-8.997 0A4.499 4.499 0 0 0 11.5 7Z"></path></svg></span><input type="text" aria-label="Go to file" role="combobox" aria-controls="file-results-list" aria-expanded="false" aria-haspopup="dialog" autoCorrect="off" spellCheck="false" placeholder="Go to file" aria-describedby="_R_5ipla9lik5_ _R_5ipla9lik5H1_" data-component="input" class="prc-components-Input-IwWrt" value=""/><span class="TextInput-icon" id="_R_5ipla9lik5H1_" aria-hidden="true" data-component="TextInput.TrailingVisual"></span></span></div><div class="d-none"></div></div><button data-component="Button" type="button" style="display:none" class="prc-Button-ButtonBase-9n-Xk NavigationMenu-module__Button__LpKgm" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3">Blame</span></span></button><div class="d-none"></div><button data-component="IconButton" type="button" data-testid="more-file-actions-button-nav-menu-wide" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk js-blob-dropdown-click NavigationMenu-module__IconButton__HpX3G prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-labelledby="_R_v4pla9lik5_" id="_R_14pla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-hidden="true" id="_R_v4pla9lik5_">More file actions</span></div></div></div><div class="react-code-view-header-element--narrow"><div class="CodeViewHeader-module__Box_7___0R6c"><div class="d-flex gap-2"><button data-component="Button" type="button" style="display:none" class="prc-Button-ButtonBase-9n-Xk NavigationMenu-module__Button__LpKgm" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3">Blame</span></span></button><div class="d-none"></div><button data-component="IconButton" type="button" data-testid="more-file-actions-button-nav-menu-narrow" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk js-blob-dropdown-click NavigationMenu-module__IconButton__HpX3G prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="medium" data-variant="default" aria-labelledby="_R_v4tla9lik5_" id="_R_14tla9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-hidden="true" id="_R_v4tla9lik5_">More file actions</span></div></div></div></div></div></div></div><div class="CodeView-module__contentWrapper__cG2JH"><div class="react-code-view-bottom-padding"><div class="BlobTopBanners-module__Box__v_nvx"></div></div> <div class="d-none"></div><div class="d-flex flex-column border rounded-2 tmp-mb-3 pl-1"><div class="LatestCommit-module__Box__B25ZT"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">Latest commit</h2><div style="width:120px" class="Skeleton Skeleton--text" data-testid="loading"> </div><div class="d-flex flex-shrink-0 gap-2"><div data-testid="latest-commit-details" class="d-none d-sm-flex flex-items-center"></div><div class="d-flex gap-2"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">History</h2><a data-component="LinkButton" href="/cht37/JavaGuide/commits/main/docs/java/collection/arrayblockingqueue-source-code.md" class="prc-Button-ButtonBase-9n-Xk d-none d-lg-flex LinkButton-module__linkButton__nFnov flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3"><span class="fgColor-default">History</span></span></span></a><div class="d-sm-none"></div><div class="d-flex d-lg-none"><a data-component="LinkButton" aria-label="View commit history for this file." href="/cht37/JavaGuide/commits/main/docs/java/collection/arrayblockingqueue-source-code.md" class="prc-Button-ButtonBase-9n-Xk LinkButton-module__linkButton__nFnov flex-items-center fgColor-default" data-loading="false" data-size="small" data-variant="invisible" aria-describedby="_R_4mlala9lik5_"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-history" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m.427 1.927 1.215 1.215a8.002 8.002 0 1 1-1.6 5.685.75.75 0 1 1 1.493-.154 6.5 6.5 0 1 0 1.18-4.458l1.358 1.358A.25.25 0 0 1 3.896 6H.25A.25.25 0 0 1 0 5.75V2.104a.25.25 0 0 1 .427-.177ZM7.75 4a.75.75 0 0 1 .75.75v2.992l2.028.812a.75.75 0 0 1-.557 1.392l-2.5-1A.751.751 0 0 1 7 8.25v-3.5A.75.75 0 0 1 7.75 4Z"></path></svg></span></span></a><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="s" data-component="Tooltip" role="tooltip" aria-hidden="true" id="_R_4mlala9lik5_">History</span></div></div></div></div></div><div class="d-flex flex-row"><div class="container BlobViewContent-module__blobContainer__DtH2d"><div class="react-code-size-details-banner BlobViewContent-module__codeSizeDetails__e5sUw"><div class="react-code-size-details-banner CodeSizeDetails-module__Box__VcD6l"><div class="text-mono CodeSizeDetails-module__Box_1__GVxQL"><div data-testid="blob-size" class="CodeSizeDetails-module__Truncate_1__lE93V prc-Truncate-Truncate-2G1eo" data-inline="true" title="36.6 KB" style="--truncate-max-width:100%"><span>773 lines (602 loc) · 36.6 KB</span></div></div></div></div><div class="react-blob-view-header-sticky BlobViewContent-module__stickyHeader__VwxB5" id="repos-sticky-header"><div class="BlobViewHeader-module__Box__yhm9u"><div class="react-blob-sticky-header"><div class="FileNameStickyHeader-module__outerWrapper__ZL4Xc FileNameStickyHeader-module__outerWrapperHidden__Zpynk"><div class="FileNameStickyHeader-module__Box_1__Hazu5"><div class="FileNameStickyHeader-module__Box_2__hoolP"><div class="FileNameStickyHeader-module__Box_3__MVKsk"><button data-component="Button" type="button" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-label="main branch" data-testid="anchor-button" data-icv-name="Switch branches/tags" class="prc-Button-ButtonBase-9n-Xk ref-selector-class RefSelectorAnchoredOverlay-module__RefSelectorOverlayBtn__a3WK3" data-loading="false" data-size="medium" data-variant="default" id="ref-picker-repos-header-ref-selector"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-git-branch" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3"><div class="RefSelectorAnchoredOverlay-module__RefSelectorOverlayContainer__yaf4p"><div style="max-width:125px" class="ref-selector-button-text-container RefSelectorAnchoredOverlay-module__RefSelectorBtnTextContainer__Di3rk"><span class="RefSelectorAnchoredOverlay-module__RefSelectorText__w_fmP">main</span></div></div></span><span data-component="trailingVisual" class="prc-Button-Visual-YNt2F prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-triangle-down" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path></svg></span></span></button><div class="d-none"></div></div><div class="FileNameStickyHeader-module__Box_4__FLhtt"><div class="Breadcrumb-module__container__Vxvev Breadcrumb-module__md__Wb1Gs"><nav data-testid="breadcrumbs" aria-labelledby="sticky-breadcrumb-heading" id="sticky-breadcrumb" class="Breadcrumb-module__nav__rQFDj"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading" id="sticky-breadcrumb-heading">Breadcrumbs</h2><ol class="Breadcrumb-module__list__ZH6zr"><li class="Breadcrumb-module__listItem__Ib0x_"><a class="Breadcrumb-module__repoLink__O2Nbs prc-Link-Link-9ZwDx" data-component="Link" data-testid="breadcrumbs-repo-link" href="/cht37/JavaGuide/tree/main" data-discover="true">JavaGuide</a></li><li class="Breadcrumb-module__listItem__Ib0x_"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__md__Wb1Gs" aria-hidden="true">/</span><a class="Breadcrumb-module__directoryLink__kQy_t prc-Link-Link-9ZwDx" data-component="Link" href="/cht37/JavaGuide/tree/main/docs" data-discover="true">docs</a></li><li class="Breadcrumb-module__listItem__Ib0x_"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__md__Wb1Gs" aria-hidden="true">/</span><a class="Breadcrumb-module__directoryLink__kQy_t prc-Link-Link-9ZwDx" data-component="Link" href="/cht37/JavaGuide/tree/main/docs/java" data-discover="true">java</a></li><li class="Breadcrumb-module__listItem__Ib0x_"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__md__Wb1Gs" aria-hidden="true">/</span><a class="Breadcrumb-module__directoryLink__kQy_t prc-Link-Link-9ZwDx" data-component="Link" href="/cht37/JavaGuide/tree/main/docs/java/collection" data-discover="true">collection</a></li></ol></nav><div data-testid="breadcrumbs-filename" class="Breadcrumb-module__filename__equZR"><span class="Breadcrumb-module__separator__eNwsI Breadcrumb-module__md__Wb1Gs" aria-hidden="true">/</span><h1 class="Breadcrumb-module__filenameHeading__MNMtw Breadcrumb-module__md__Wb1Gs prc-Heading-Heading-MtWFE" data-component="Heading" tabindex="-1" id="sticky-file-name-id">arrayblockingqueue-source-code.md</h1></div><button data-component="IconButton" type="button" class="prc-Button-ButtonBase-9n-Xk ml-2 prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_7lcpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="CopyToClipboardIconButton-module__tooltip__WyiwL prc-TooltipV2-Tooltip-tLeuB" data-direction="s" data-component="Tooltip" aria-label="Copy path" aria-hidden="true" id="_R_7lcpala9lik5_">Copy path</span></div></div></div><button data-component="Button" type="button" class="prc-Button-ButtonBase-9n-Xk FileNameStickyHeader-module__Button__LSEU_ FileNameStickyHeader-module__GoToTopButton__nxAFn" data-loading="false" data-size="small" data-variant="invisible"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="leadingVisual" class="prc-Button-Visual-YNt2F prc-Button-LeadingVisual-UySKu prc-Button-VisualWrap-E4cnq"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-arrow-up" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M3.47 7.78a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0l4.25 4.25a.751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018L9 4.81v7.44a.75.75 0 0 1-1.5 0V4.81L4.53 7.78a.75.75 0 0 1-1.06 0Z"></path></svg></span><span data-component="text" class="prc-Button-Label-FWkx3">Top</span></span></button></div></div></div><div class="BlobViewHeader-module__Box_1__VEmuQ"><h2 class="sr-only ScreenReaderHeading-module__userSelectNone__rwWIk prc-Heading-Heading-MtWFE" data-component="Heading" data-testid="screen-reader-heading">File metadata and controls</h2><div class="BlobViewHeader-module__Box_2__icUs2"><ul aria-label="File view" class="prc-SegmentedControl-SegmentedControl-lqIXp BlobTabButtons-module__SegmentedControl__jen2u" data-variant="default" data-size="small" data-component="SegmentedControl"><li class="prc-SegmentedControl-Item-tSCQh" data-selected="" data-component="SegmentedControl.Button"><button aria-pressed="true" class="prc-SegmentedControl-Button-E48xz" type="button" style="--separator-color:transparent"><span class="prc-SegmentedControl-Content-1COlk segmentedControl-content"><div class="prc-SegmentedControl-Text-7S2y2 segmentedControl-text" data-text="Preview">Preview</div></span></button></li><li class="prc-SegmentedControl-Item-tSCQh" data-component="SegmentedControl.Button"><button aria-pressed="false" class="prc-SegmentedControl-Button-E48xz" type="button" style="--separator-color:var(--borderColor-default)"><span class="prc-SegmentedControl-Content-1COlk segmentedControl-content"><div class="prc-SegmentedControl-Text-7S2y2 segmentedControl-text" data-text="Code">Code</div></span></button></li><li class="prc-SegmentedControl-Item-tSCQh" data-component="SegmentedControl.Button"><button aria-pressed="false" class="prc-SegmentedControl-Button-E48xz" type="button" style="--separator-color:var(--borderColor-default)"><span class="prc-SegmentedControl-Content-1COlk segmentedControl-content"><div class="prc-SegmentedControl-Text-7S2y2 segmentedControl-text" data-text="Blame">Blame</div></span></button></li></ul><div class="d-none"></div><div class="react-code-size-details-in-header CodeSizeDetails-module__Box__VcD6l"><div class="text-mono CodeSizeDetails-module__Box_1__GVxQL"><div data-testid="blob-size" class="CodeSizeDetails-module__Truncate_1__lE93V prc-Truncate-Truncate-2G1eo" data-inline="true" title="36.6 KB" style="--truncate-max-width:100%"><span>773 lines (602 loc) · 36.6 KB</span></div></div></div></div><div class="BlobViewHeader-module__Box_3__ng6v2"><div class="d-none"></div><div class="react-blob-header-edit-and-raw-actions BlobViewHeader-module__Box_4__J4Y4W"><div class="d-none"></div><div class="prc-ButtonGroup-ButtonGroup-vFUrY" data-component="ButtonGroup"><div class="prc-ButtonGroup-Item-PqvDl"><a data-component="LinkButton" href="https://github.com/cht37/JavaGuide/raw/refs/heads/main/docs/java/collection/arrayblockingqueue-source-code.md" data-testid="raw-button" class="prc-Button-ButtonBase-9n-Xk LinkButton-module__linkButton__nFnov BlobViewHeader-module__LinkButton__X9kx2" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default"><span data-component="buttonContent" data-align="center" class="prc-Button-ButtonContent-Iohp5"><span data-component="text" class="prc-Button-Label-FWkx3">Raw</span></span></a></div><div class="prc-ButtonGroup-Item-PqvDl"><button data-component="IconButton" type="button" data-testid="copy-raw-button" class="prc-Button-ButtonBase-9n-Xk prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default" aria-labelledby="_R_qaucpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-copy" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="n" data-component="Tooltip" aria-hidden="true" id="_R_qaucpala9lik5_">Copy raw file</span></div><div class="prc-ButtonGroup-Item-PqvDl"><button data-component="IconButton" type="button" data-testid="download-raw-button" class="prc-Button-ButtonBase-9n-Xk BlobViewHeader-module__downloadButton__ef459 prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="default" aria-labelledby="_R_eaucpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-download" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14Z"></path><path d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.749.749 0 1 1 1.06 1.06l-3.25 3.25a.749.749 0 0 1-1.06 0L4.22 6.78a.749.749 0 1 1 1.06-1.06l1.97 1.969Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="n" data-component="Tooltip" aria-hidden="true" id="_R_eaucpala9lik5_">Download raw file</span></div></div></div><button data-component="IconButton" type="button" aria-pressed="false" class="prc-Button-ButtonBase-9n-Xk tmp-mr-2 TableOfContents-module__IconButton__jrlNM prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_3ucpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-list-unordered" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M5.75 2.5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5Zm0 5h8.5a.75.75 0 0 1 0 1.5h-8.5a.75.75 0 0 1 0-1.5ZM2 14a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-6a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM2 4a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="n" data-component="Tooltip" aria-hidden="true" id="_R_3ucpala9lik5_">Outline</span><div class="react-blob-header-edit-and-raw-actions-combined"><button data-component="IconButton" type="button" title="More file actions" data-testid="more-file-actions-button" aria-haspopup="true" aria-expanded="false" tabindex="0" class="prc-Button-ButtonBase-9n-Xk js-blob-dropdown-click BlobViewHeader-module__IconButton__XrMQY prc-Button-IconButton-fyge7" data-loading="false" data-no-visuals="true" data-size="small" data-variant="invisible" aria-labelledby="_R_fkecpala9lik5_" id="_R_kecpala9lik5_"><svg data-component="Octicon" aria-hidden="true" focusable="false" class="octicon octicon-kebab-horizontal" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" display="inline-block" overflow="visible" style="vertical-align:text-bottom"><path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path></svg></button><span class="prc-TooltipV2-Tooltip-tLeuB" data-direction="nw" data-component="Tooltip" aria-hidden="true" id="_R_fkecpala9lik5_">Edit and raw actions</span></div></div></div></div><div></div></div><div class="BlobViewContent-module__blobContentWrapper__JS0W6"><section aria-labelledby="file-name-id-wide file-name-id-mobile" class="BlobContent-module__blobContentSection__VOgZq BlobContent-module__blobContentSectionMarkdown__mPLOK" style="margin-top:46px"><div class="js-snippet-clipboard-copy-unpositioned BlobContent-module__markdownBlob__T8jpG" data-hpc="true" containertiming="hpc"><article class="markdown-body entry-content container-lg" itemprop="text"><markdown-accessiblity-table><table>
  <tbody>
  <tr>
    <th>title</th>
    <td>ArrayBlockingQueue 源码分析</td>
  </tr>
  <tr>
    <th>category</th>
    <td>Java</td>
  </tr>
  <tr>
    <th>tag</th>
    <td><table>
  <tbody>
  <tr>
  <td><div dir="auto">Java集合</div></td>
  </tr>
  </tbody>
</table>
</td>
  </tr>
  </tbody>
</table></markdown-accessiblity-table>

<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">阻塞队列简介</h2><a id="user-content-阻塞队列简介" class="anchor" aria-label="Permalink: 阻塞队列简介" href="#阻塞队列简介"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">阻塞队列的历史</h3><a id="user-content-阻塞队列的历史" class="anchor" aria-label="Permalink: 阻塞队列的历史" href="#阻塞队列的历史"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">Java 阻塞队列的历史可以追溯到 JDK1.5 版本，当时 Java 平台增加了 <code>java.util.concurrent</code>，即我们常说的 JUC 包，其中包含了各种并发流程控制工具、并发容器、原子类等。这其中自然也包含了我们这篇文章所讨论的阻塞队列。</p>
<p dir="auto">为了解决高并发场景下多线程之间数据共享的问题，JDK1.5 版本中出现了 <code>ArrayBlockingQueue</code> 和 <code>LinkedBlockingQueue</code>，它们是带有生产者-消费者模式实现的并发容器。其中，<code>ArrayBlockingQueue</code> 是有界队列，即添加的元素达到上限之后，再次添加就会被阻塞或者抛出异常。而 <code>LinkedBlockingQueue</code> 则由链表构成的队列，正是因为链表的特性，所以 <code>LinkedBlockingQueue</code> 在添加元素上并不会向 <code>ArrayBlockingQueue</code> 那样有着较多的约束，所以 <code>LinkedBlockingQueue</code> 设置队列是否有界是可选的(注意这里的无界并不是指可以添加任务数量的元素，而是说队列的大小默认为 <code>Integer.MAX_VALUE</code>，近乎于无限大)。</p>
<p dir="auto">随着 Java 的不断发展，JDK 后续的几个版本又对阻塞队列进行了不少的更新和完善:</p>
<ol dir="auto">
<li>JDK1.6 版本:增加 <code>SynchronousQueue</code>，一个不存储元素的阻塞队列。</li>
<li>JDK1.7 版本:增加 <code>TransferQueue</code>，一个支持更多操作的阻塞队列。</li>
<li>JDK1.8 版本:增加 <code>DelayQueue</code>，一个支持延迟获取元素的阻塞队列。</li>
</ol>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">阻塞队列的思想</h3><a id="user-content-阻塞队列的思想" class="anchor" aria-label="Permalink: 阻塞队列的思想" href="#阻塞队列的思想"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">阻塞队列就是典型的生产者-消费者模型，它可以做到以下几点:</p>
<ol dir="auto">
<li>当阻塞队列数据为空时，所有的消费者线程都会被阻塞，等待队列非空。</li>
<li>当生产者往队列里填充数据后，队列就会通知消费者队列非空，消费者此时就可以进来消费。</li>
<li>当阻塞队列因为消费者消费过慢或者生产者存放元素过快导致队列填满时无法容纳新元素时，生产者就会被阻塞，等待队列非满时继续存放元素。</li>
<li>当消费者从队列中消费一个元素之后，队列就会通知生产者队列非满，生产者可以继续填充数据了。</li>
</ol>
<p dir="auto">总结一下：阻塞队列就说基于非空和非满两个条件实现生产者和消费者之间的交互，尽管这些交互流程和等待通知的机制实现非常复杂，好在 Doug Lea 的操刀之下已将阻塞队列的细节屏蔽，我们只需调用 <code>put</code>、<code>take</code>、<code>offfer</code>、<code>poll</code> 等 API 即可实现多线程之间的生产和消费。</p>
<p dir="auto">这也使得阻塞队列在多线程开发中有着广泛的运用，最常见的例子无非是我们的线程池,从源码中我们就能看出当核心线程无法及时处理任务时，这些任务都会扔到 <code>workQueue</code> 中。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public ThreadPoolExecutor(int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue&lt;Runnable&gt; workQueue,
                            ThreadFactory threadFactory,
                            RejectedExecutionHandler handler) {// ...}"><pre><span class="pl-k">public</span> <span class="pl-smi">ThreadPoolExecutor</span><span class="pl-en"></span>(<span class="pl-smi">int</span> <span class="pl-s1">corePoolSize</span>,
                            <span class="pl-smi">int</span> <span class="pl-s1">maximumPoolSize</span>,
                            <span class="pl-smi">long</span> <span class="pl-s1">keepAliveTime</span>,
                            <span class="pl-smi">TimeUnit</span> <span class="pl-s1">unit</span>,
                            <span class="pl-smi">BlockingQueue</span>&lt;<span class="pl-smi">Runnable</span>&gt; <span class="pl-s1">workQueue</span>,
                            <span class="pl-smi">ThreadFactory</span> <span class="pl-s1">threadFactory</span>,
                            <span class="pl-smi">RejectedExecutionHandler</span> <span class="pl-s1">handler</span>) {<span class="pl-c">// ...}</span></pre></div>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">ArrayBlockingQueue 常见方法及测试</h2><a id="user-content-arrayblockingqueue-常见方法及测试" class="anchor" aria-label="Permalink: ArrayBlockingQueue 常见方法及测试" href="#arrayblockingqueue-常见方法及测试"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">简单了解了阻塞队列的历史之后，我们就开始重点讨论本篇文章所要介绍的并发容器——<code>ArrayBlockingQueue</code>。为了后续更加深入的了解 <code>ArrayBlockingQueue</code>，我们不妨基于下面几个实例了解以下 <code>ArrayBlockingQueue</code> 的使用。</p>
<p dir="auto">先看看第一个例子，我们这里会用两个线程分别模拟生产者和消费者，生产者生产完会使用 <code>put</code> 方法生产 10 个元素给消费者进行消费，当队列元素达到我们设置的上限 5 时，<code>put</code> 方法就会阻塞。
同理消费者也会通过 <code>take</code> 方法消费元素，当队列为空时，<code>take</code> 方法就会阻塞消费者线程。这里笔者为了保证消费者能够在消费完 10 个元素后及时退出。便通过倒计时门闩，来控制消费者结束，生产者在这里只会生产 10 个元素。当消费者将 10 个元素消费完成之后，按下倒计时门闩，所有线程都会停止。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public class ProducerConsumerExample {

    public static void main(String[] args) throws InterruptedException {

        // 创建一个大小为 5 的 ArrayBlockingQueue
        ArrayBlockingQueue&lt;Integer&gt; queue = new ArrayBlockingQueue&lt;&gt;(5);

        // 创建生产者线程
        Thread producer = new Thread(() -&gt; {
            try {
                for (int i = 1; i &lt;= 10; i++) {
                    // 向队列中添加元素，如果队列已满则阻塞等待
                    queue.put(i);
                    System.out.println(&quot;生产者添加元素：&quot; + i);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });

        CountDownLatch countDownLatch = new CountDownLatch(1);

        // 创建消费者线程
        Thread consumer = new Thread(() -&gt; {
            try {
                int count = 0;
                while (true) {

                    // 从队列中取出元素，如果队列为空则阻塞等待
                    int element = queue.take();
                    System.out.println(&quot;消费者取出元素：&quot; + element);
                    ++count;
                    if (count == 10) {
                        break;
                    }
                }

                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        });

        // 启动线程
        producer.start();
        consumer.start();

        // 等待线程结束
        producer.join();
        consumer.join();

        countDownLatch.await();

        producer.interrupt();
        consumer.interrupt();
    }

}"><pre><span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">ProducerConsumerExample</span> {

    <span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-smi">void</span> <span class="pl-en">main</span>(<span class="pl-smi">String</span>[] <span class="pl-s1">args</span>) <span class="pl-k">throws</span> <span class="pl-smi">InterruptedException</span> {

        <span class="pl-c">// 创建一个大小为 5 的 ArrayBlockingQueue</span>
        <span class="pl-smi">ArrayBlockingQueue</span>&lt;<span class="pl-smi">Integer</span>&gt; <span class="pl-s1">queue</span> = <span class="pl-k">new</span> <span class="pl-smi">ArrayBlockingQueue</span>&lt;&gt;(<span class="pl-c1">5</span>);

        <span class="pl-c">// 创建生产者线程</span>
        <span class="pl-smi">Thread</span> <span class="pl-s1">producer</span> = <span class="pl-k">new</span> <span class="pl-smi">Thread</span>(() -&gt; {
            <span class="pl-k">try</span> {
                <span class="pl-k">for</span> (<span class="pl-smi">int</span> <span class="pl-s1">i</span> = <span class="pl-c1">1</span>; <span class="pl-s1">i</span> &lt;= <span class="pl-c1">10</span>; <span class="pl-s1">i</span>++) {
                    <span class="pl-c">// 向队列中添加元素，如果队列已满则阻塞等待</span>
                    <span class="pl-s1">queue</span>.<span class="pl-en">put</span>(<span class="pl-s1">i</span>);
                    <span class="pl-smi">System</span>.<span class="pl-s1">out</span>.<span class="pl-en">println</span>(<span class="pl-s">"生产者添加元素："</span> + <span class="pl-s1">i</span>);
                }
            } <span class="pl-k">catch</span> (<span class="pl-smi">InterruptedException</span> <span class="pl-s1">e</span>) {
                <span class="pl-s1">e</span>.<span class="pl-en">printStackTrace</span>();
            }

        });

        <span class="pl-smi">CountDownLatch</span> <span class="pl-s1">countDownLatch</span> = <span class="pl-k">new</span> <span class="pl-smi">CountDownLatch</span>(<span class="pl-c1">1</span>);

        <span class="pl-c">// 创建消费者线程</span>
        <span class="pl-smi">Thread</span> <span class="pl-s1">consumer</span> = <span class="pl-k">new</span> <span class="pl-smi">Thread</span>(() -&gt; {
            <span class="pl-k">try</span> {
                <span class="pl-smi">int</span> <span class="pl-s1">count</span> = <span class="pl-c1">0</span>;
                <span class="pl-k">while</span> (<span class="pl-c1">true</span>) {

                    <span class="pl-c">// 从队列中取出元素，如果队列为空则阻塞等待</span>
                    <span class="pl-smi">int</span> <span class="pl-s1">element</span> = <span class="pl-s1">queue</span>.<span class="pl-en">take</span>();
                    <span class="pl-smi">System</span>.<span class="pl-s1">out</span>.<span class="pl-en">println</span>(<span class="pl-s">"消费者取出元素："</span> + <span class="pl-s1">element</span>);
                    ++<span class="pl-s1">count</span>;
                    <span class="pl-k">if</span> (<span class="pl-s1">count</span> == <span class="pl-c1">10</span>) {
                        <span class="pl-k">break</span>;
                    }
                }

                <span class="pl-s1">countDownLatch</span>.<span class="pl-en">countDown</span>();
            } <span class="pl-k">catch</span> (<span class="pl-smi">InterruptedException</span> <span class="pl-s1">e</span>) {
                <span class="pl-s1">e</span>.<span class="pl-en">printStackTrace</span>();
            }

        });

        <span class="pl-c">// 启动线程</span>
        <span class="pl-s1">producer</span>.<span class="pl-en">start</span>();
        <span class="pl-s1">consumer</span>.<span class="pl-en">start</span>();

        <span class="pl-c">// 等待线程结束</span>
        <span class="pl-s1">producer</span>.<span class="pl-en">join</span>();
        <span class="pl-s1">consumer</span>.<span class="pl-en">join</span>();

        <span class="pl-s1">countDownLatch</span>.<span class="pl-en">await</span>();

        <span class="pl-s1">producer</span>.<span class="pl-en">interrupt</span>();
        <span class="pl-s1">consumer</span>.<span class="pl-en">interrupt</span>();
    }

}</pre></div>
<p dir="auto">代码输出结果如下，可以看到只有生产者往队列中投放元素之后消费者才能消费，这也就意味着当队列中没有数据的时消费者就会阻塞，等待队列非空再继续消费。</p>
<div class="highlight highlight-source-c++ notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="生产者添加元素：1
生产者添加元素：2
消费者取出元素：1
消费者取出元素：2
消费者取出元素：3
生产者添加元素：3
生产者添加元素：4
生产者添加元素：5
消费者取出元素：4
生产者添加元素：6
消费者取出元素：5
生产者添加元素：7
生产者添加元素：8
生产者添加元素：9
生产者添加元素：10
消费者取出元素：6
消费者取出元素：7
消费者取出元素：8
消费者取出元素：9
消费者取出元素：10"><pre>生产者添加元素：<span class="pl-c1">1</span>
生产者添加元素：<span class="pl-c1">2</span>
消费者取出元素：<span class="pl-c1">1</span>
消费者取出元素：<span class="pl-c1">2</span>
消费者取出元素：<span class="pl-c1">3</span>
生产者添加元素：<span class="pl-c1">3</span>
生产者添加元素：<span class="pl-c1">4</span>
生产者添加元素：<span class="pl-c1">5</span>
消费者取出元素：<span class="pl-c1">4</span>
生产者添加元素：<span class="pl-c1">6</span>
消费者取出元素：<span class="pl-c1">5</span>
生产者添加元素：<span class="pl-c1">7</span>
生产者添加元素：<span class="pl-c1">8</span>
生产者添加元素：<span class="pl-c1">9</span>
生产者添加元素：<span class="pl-c1">10</span>
消费者取出元素：<span class="pl-c1">6</span>
消费者取出元素：<span class="pl-c1">7</span>
消费者取出元素：<span class="pl-c1">8</span>
消费者取出元素：<span class="pl-c1">9</span>
消费者取出元素：<span class="pl-c1">10</span></pre></div>
<p dir="auto">了解了 <code>put</code>、<code>take</code> 这两个会阻塞的存和取方法之后，我我们再来看看阻塞队列中非阻塞的入队和出队方法 <code>offer</code> 和 <code>poll</code>。</p>
<p dir="auto">如下所示，我们设置了一个大小为 3 的阻塞队列，我们会尝试在队列用 offer 方法存放 4 个元素，然后再从队列中用 <code>poll</code> 尝试取 4 次。</p>
<div class="highlight highlight-source-c++ notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public class OfferPollExample {

    public static void main(String[] args) {
        // 创建一个大小为 3 的 ArrayBlockingQueue
        ArrayBlockingQueue&lt;String&gt; queue = new ArrayBlockingQueue&lt;&gt;(3);

        // 向队列中添加元素
        System.out.println(queue.offer(&quot;A&quot;));
        System.out.println(queue.offer(&quot;B&quot;));
        System.out.println(queue.offer(&quot;C&quot;));

        // 尝试向队列中添加元素，但队列已满，返回 false
        System.out.println(queue.offer(&quot;D&quot;));

        // 从队列中取出元素
        System.out.println(queue.poll());
        System.out.println(queue.poll());
        System.out.println(queue.poll());

        // 尝试从队列中取出元素，但队列已空，返回 null
        System.out.println(queue.poll());
    }

}"><pre>public <span class="pl-k">class</span> <span class="pl-en">OfferPollExample</span> {

    public <span class="pl-k">static</span> <span class="pl-k">void</span> <span class="pl-en">main</span>(String[] args) {
        <span class="pl-c"><span class="pl-c">//</span> 创建一个大小为 3 的 ArrayBlockingQueue</span>
        ArrayBlockingQueue&lt;String&gt; queue = <span class="pl-k">new</span> ArrayBlockingQueue&lt;&gt;(<span class="pl-c1">3</span>);

        <span class="pl-c"><span class="pl-c">//</span> 向队列中添加元素</span>
        System.<span class="pl-smi">out</span>.<span class="pl-c1">println</span>(queue.<span class="pl-c1">offer</span>(<span class="pl-s"><span class="pl-pds">"</span>A<span class="pl-pds">"</span></span>));
        System.<span class="pl-smi">out</span>.<span class="pl-c1">println</span>(queue.<span class="pl-c1">offer</span>(<span class="pl-s"><span class="pl-pds">"</span>B<span class="pl-pds">"</span></span>));
        System.<span class="pl-smi">out</span>.<span class="pl-c1">println</span>(queue.<span class="pl-c1">offer</span>(<span class="pl-s"><span class="pl-pds">"</span>C<span class="pl-pds">"</span></span>));

        <span class="pl-c"><span class="pl-c">//</span> 尝试向队列中添加元素，但队列已满，返回 false</span>
        System.<span class="pl-smi">out</span>.<span class="pl-c1">println</span>(queue.<span class="pl-c1">offer</span>(<span class="pl-s"><span class="pl-pds">"</span>D<span class="pl-pds">"</span></span>));

        <span class="pl-c"><span class="pl-c">//</span> 从队列中取出元素</span>
        System.<span class="pl-smi">out</span>.<span class="pl-c1">println</span>(queue.<span class="pl-c1">poll</span>());
        System.<span class="pl-smi">out</span>.<span class="pl-c1">println</span>(queue.<span class="pl-c1">poll</span>());
        System.<span class="pl-smi">out</span>.<span class="pl-c1">println</span>(queue.<span class="pl-c1">poll</span>());

        <span class="pl-c"><span class="pl-c">//</span> 尝试从队列中取出元素，但队列已空，返回 null</span>
        System.<span class="pl-smi">out</span>.<span class="pl-c1">println</span>(queue.<span class="pl-c1">poll</span>());
    }

}<span class="pl-ii"></span></pre></div>
<p dir="auto">最终代码的输出结果如下，可以看到因为队列的大小为 3 的缘故，我们前 3 次存放到队列的结果为 true，第 4 次存放时，由于队列已满，所以存放结果返回 false。这也是为什么我们后续的 <code>poll</code> 方法只得到了 3 个元素的值。</p>
<div class="highlight highlight-source-c++ notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="true
true
true
false
A
B
C
null"><pre><span class="pl-c1">true</span>
<span class="pl-c1">true</span>
<span class="pl-c1">true</span>
<span class="pl-c1">false</span>
A
B
C
null</pre></div>
<p dir="auto">了解了阻塞存取和非阻塞存取，我们再来看看阻塞队列的一个比较特殊的操作，某些场景下，我们希望能够一次性将阻塞队列的结果存到列表中再进行批量操作，我们就可以使用阻塞队列的 <code>drainTo</code> 方法，这个方法会一次性将队列中所有元素存放到列表，如果队列中有元素，且成功存到 list 中则 <code>drainTo</code> 会返回本次转移到 list 中的元素数，反之若队列为空，<code>drainTo</code> 则直接返回 0。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public class DrainToExample {

    public static void main(String[] args) {
        // 创建一个大小为 5 的 ArrayBlockingQueue
        ArrayBlockingQueue&lt;Integer&gt; queue = new ArrayBlockingQueue&lt;&gt;(5);

        // 向队列中添加元素
        queue.add(1);
        queue.add(2);
        queue.add(3);
        queue.add(4);
        queue.add(5);

        // 创建一个 List，用于存储从队列中取出的元素
        List&lt;Integer&gt; list = new ArrayList&lt;&gt;();

        // 从队列中取出所有元素，并添加到 List 中
        queue.drainTo(list);

        // 输出 List 中的元素
        System.out.println(list);
    }

}"><pre><span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">DrainToExample</span> {

    <span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-smi">void</span> <span class="pl-en">main</span>(<span class="pl-smi">String</span>[] <span class="pl-s1">args</span>) {
        <span class="pl-c">// 创建一个大小为 5 的 ArrayBlockingQueue</span>
        <span class="pl-smi">ArrayBlockingQueue</span>&lt;<span class="pl-smi">Integer</span>&gt; <span class="pl-s1">queue</span> = <span class="pl-k">new</span> <span class="pl-smi">ArrayBlockingQueue</span>&lt;&gt;(<span class="pl-c1">5</span>);

        <span class="pl-c">// 向队列中添加元素</span>
        <span class="pl-s1">queue</span>.<span class="pl-en">add</span>(<span class="pl-c1">1</span>);
        <span class="pl-s1">queue</span>.<span class="pl-en">add</span>(<span class="pl-c1">2</span>);
        <span class="pl-s1">queue</span>.<span class="pl-en">add</span>(<span class="pl-c1">3</span>);
        <span class="pl-s1">queue</span>.<span class="pl-en">add</span>(<span class="pl-c1">4</span>);
        <span class="pl-s1">queue</span>.<span class="pl-en">add</span>(<span class="pl-c1">5</span>);

        <span class="pl-c">// 创建一个 List，用于存储从队列中取出的元素</span>
        <span class="pl-smi">List</span>&lt;<span class="pl-smi">Integer</span>&gt; <span class="pl-s1">list</span> = <span class="pl-k">new</span> <span class="pl-smi">ArrayList</span>&lt;&gt;();

        <span class="pl-c">// 从队列中取出所有元素，并添加到 List 中</span>
        <span class="pl-s1">queue</span>.<span class="pl-en">drainTo</span>(<span class="pl-s1">list</span>);

        <span class="pl-c">// 输出 List 中的元素</span>
        <span class="pl-smi">System</span>.<span class="pl-s1">out</span>.<span class="pl-en">println</span>(<span class="pl-s1">list</span>);
    }

}</pre></div>
<p dir="auto">代码输出结果如下</p>
<div class="highlight highlight-source-c++ notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="[1, 2, 3, 4, 5]"><pre>[<span class="pl-c1">1</span>, <span class="pl-c1">2</span>, <span class="pl-c1">3</span>, <span class="pl-c1">4</span>, <span class="pl-c1">5</span>]</pre></div>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">ArrayBlockingQueue 源码分析</h2><a id="user-content-arrayblockingqueue-源码分析" class="anchor" aria-label="Permalink: ArrayBlockingQueue 源码分析" href="#arrayblockingqueue-源码分析"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">自此我们对阻塞队列的使用有了基本的印象，接下来我们就可以进一步了解一下 <code>ArrayBlockingQueue</code> 的工作机制了。</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">整体设计</h3><a id="user-content-整体设计" class="anchor" aria-label="Permalink: 整体设计" href="#整体设计"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">在了解 <code>ArrayBlockingQueue</code> 的具体细节之前，我们先来看看 <code>ArrayBlockingQueue</code> 的类图。</p>
<p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/9bfb751edde6977973be217cd7e3da2282848fb22f0c38830e5a6f2296296cf8/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f6172726179626c6f636b696e6771756575652d636c6173732d6469616772616d2e706e67"><img src="https://camo.githubusercontent.com/9bfb751edde6977973be217cd7e3da2282848fb22f0c38830e5a6f2296296cf8/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f6172726179626c6f636b696e6771756575652d636c6173732d6469616772616d2e706e67" alt="ArrayBlockingQueue 类图" data-canonical-src="https://oss.javaguide.cn/github/javaguide/java/collection/arrayblockingqueue-class-diagram.png" style="max-width: 100%;"></a></p>
<p dir="auto">从图中我们可以看出，<code>ArrayBlockingQueue</code> 继承了阻塞队列 <code>BlockingQueue</code> 这个接口，不难猜出通过继承 <code>BlockingQueue</code> 这个接口之后，<code>ArrayBlockingQueue</code> 就拥有了阻塞队列那些常见的操作行为。</p>
<p dir="auto">同时， <code>ArrayBlockingQueue</code> 还继承了 <code>AbstractQueue</code> 这个抽象类，这个继承了 <code>AbstractCollection</code> 和 <code>Queue</code> 的抽象类，从抽象类的特定和语义我们也可以猜出，这个继承关系使得 <code>ArrayBlockingQueue</code> 拥有了队列的常见操作。</p>
<p dir="auto">所以我们是否可以得出这样一个结论，通过继承 <code>AbstractQueue</code> 获得队列所有的操作模板，其实现的入队和出队操作的整体框架。然后 <code>ArrayBlockingQueue</code> 通过继承 <code>BlockingQueue</code> 获取到阻塞队列的常见操作并将这些操作实现，填充到 <code>AbstractQueue</code> 模板方法的细节中，由此 <code>ArrayBlockingQueue</code> 成为一个完整的阻塞队列。</p>
<p dir="auto">为了印证这一点，我们到源码中一探究竟。首先我们先来看看 <code>AbstractQueue</code>，从类的继承关系我们可以大致得出，它通过 <code>AbstractCollection</code> 获得了集合的常见操作方法，然后通过 <code>Queue</code> 接口获得了队列的特性。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public abstract class AbstractQueue&lt;E&gt;
    extends AbstractCollection&lt;E&gt;
    implements Queue&lt;E&gt; {
       //...
}"><pre><span class="pl-k">public</span> <span class="pl-k">abstract</span> <span class="pl-k">class</span> <span class="pl-smi">AbstractQueue</span>&lt;<span class="pl-smi">E</span>&gt;
    <span class="pl-k">extends</span> <span class="pl-smi">AbstractCollection</span>&lt;<span class="pl-smi">E</span>&gt;
    <span class="pl-k">implements</span> <span class="pl-smi">Queue</span>&lt;<span class="pl-smi">E</span>&gt; {
       <span class="pl-c">//...</span>
}</pre></div>
<p dir="auto">对于集合的操作无非是增删改查，所以我们不妨从添加方法入手，从源码中我们可以看到，它实现了 <code>AbstractCollection</code> 的 <code>add</code> 方法，其内部逻辑如下:</p>
<ol dir="auto">
<li>调用继承 <code>Queue</code> 接口的来的 <code>offer</code> 方法，如果 <code>offer</code> 成功则返回 <code>true</code>。</li>
<li>如果 <code>offer</code> 失败，即代表当前元素入队失败直接抛异常。</li>
</ol>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public boolean add(E e) {
  if (offer(e))
      return true;
  else
      throw new IllegalStateException(&quot;Queue full&quot;);
}"><pre><span class="pl-k">public</span> <span class="pl-smi">boolean</span> <span class="pl-en">add</span>(<span class="pl-smi">E</span> <span class="pl-s1">e</span>) {
  <span class="pl-k">if</span> (<span class="pl-en">offer</span>(<span class="pl-s1">e</span>))
      <span class="pl-k">return</span> <span class="pl-c1">true</span>;
  <span class="pl-k">else</span>
      <span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-smi">IllegalStateException</span>(<span class="pl-s">"Queue full"</span>);
}</pre></div>
<p dir="auto">而 <code>AbstractQueue</code> 中并没有对 <code>Queue</code> 的 <code>offer</code> 的实现，很明显这样做的目的是定义好了 <code>add</code> 的核心逻辑，将 <code>offer</code> 的细节交由其子类即我们的 <code>ArrayBlockingQueue</code> 实现。</p>
<p dir="auto">到此，我们对于抽象类 <code>AbstractQueue</code> 的分析就结束了，我们继续看看 <code>ArrayBlockingQueue</code> 中另一个重要的继承接口 <code>BlockingQueue</code>。</p>
<p dir="auto">点开 <code>BlockingQueue</code> 之后，我们可以看到这个接口同样继承了 <code>Queue</code> 接口，这就意味着它也具备了队列所拥有的所有行为。同时，它还定义了自己所需要实现的方法。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public interface BlockingQueue&lt;E&gt; extends Queue&lt;E&gt; {

     //元素入队成功返回true，反之则会抛出异常IllegalStateException
    boolean add(E e);

     //元素入队成功返回true，反之返回false
    boolean offer(E e);

     //元素入队成功则直接返回，如果队列已满元素不可入队则将线程阻塞，因为阻塞期间可能会被打断，所以这里方法签名抛出了InterruptedException
    void put(E e) throws InterruptedException;

   //和上一个方法一样,只不过队列满时只会阻塞单位为unit，时间为timeout的时长，如果在等待时长内没有入队成功则直接返回false。
    boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException;

    //从队头取出一个元素，如果队列为空则阻塞等待，因为会阻塞线程的缘故，所以该方法可能会被打断，所以签名定义了InterruptedException
    E take() throws InterruptedException;

      //取出队头的元素并返回，如果当前队列为空则阻塞等待timeout且单位为unit的时长，如果这个时间段没有元素则直接返回null。
    E poll(long timeout, TimeUnit unit)
        throws InterruptedException;

      //获取队列剩余元素个数
    int remainingCapacity();

     //删除我们指定的对象，如果成功返回true，反之返回false。
    boolean remove(Object o);

    //判断队列中是否包含指定元素
    public boolean contains(Object o);

     //将队列中的元素全部存到指定的集合中
    int drainTo(Collection&lt;? super E&gt; c);

    //转移maxElements个元素到集合中
    int drainTo(Collection&lt;? super E&gt; c, int maxElements);
}"><pre><span class="pl-k">public</span> <span class="pl-k">interface</span> <span class="pl-smi">BlockingQueue</span>&lt;<span class="pl-smi">E</span>&gt; <span class="pl-k">extends</span> <span class="pl-smi">Queue</span>&lt;<span class="pl-smi">E</span>&gt; {

     <span class="pl-c">//元素入队成功返回true，反之则会抛出异常IllegalStateException</span>
    <span class="pl-smi">boolean</span> <span class="pl-en">add</span>(<span class="pl-smi">E</span> <span class="pl-s1">e</span>);

     <span class="pl-c">//元素入队成功返回true，反之返回false</span>
    <span class="pl-smi">boolean</span> <span class="pl-en">offer</span>(<span class="pl-smi">E</span> <span class="pl-s1">e</span>);

     <span class="pl-c">//元素入队成功则直接返回，如果队列已满元素不可入队则将线程阻塞，因为阻塞期间可能会被打断，所以这里方法签名抛出了InterruptedException</span>
    <span class="pl-smi">void</span> <span class="pl-en">put</span>(<span class="pl-smi">E</span> <span class="pl-s1">e</span>) <span class="pl-k">throws</span> <span class="pl-smi">InterruptedException</span>;

   <span class="pl-c">//和上一个方法一样,只不过队列满时只会阻塞单位为unit，时间为timeout的时长，如果在等待时长内没有入队成功则直接返回false。</span>
    <span class="pl-smi">boolean</span> <span class="pl-en">offer</span>(<span class="pl-smi">E</span> <span class="pl-s1">e</span>, <span class="pl-smi">long</span> <span class="pl-s1">timeout</span>, <span class="pl-smi">TimeUnit</span> <span class="pl-s1">unit</span>)
        <span class="pl-k">throws</span> <span class="pl-smi">InterruptedException</span>;

    <span class="pl-c">//从队头取出一个元素，如果队列为空则阻塞等待，因为会阻塞线程的缘故，所以该方法可能会被打断，所以签名定义了InterruptedException</span>
    <span class="pl-smi">E</span> <span class="pl-en">take</span>() <span class="pl-k">throws</span> <span class="pl-smi">InterruptedException</span>;

      <span class="pl-c">//取出队头的元素并返回，如果当前队列为空则阻塞等待timeout且单位为unit的时长，如果这个时间段没有元素则直接返回null。</span>
    <span class="pl-smi">E</span> <span class="pl-en">poll</span>(<span class="pl-smi">long</span> <span class="pl-s1">timeout</span>, <span class="pl-smi">TimeUnit</span> <span class="pl-s1">unit</span>)
        <span class="pl-k">throws</span> <span class="pl-smi">InterruptedException</span>;

      <span class="pl-c">//获取队列剩余元素个数</span>
    <span class="pl-smi">int</span> <span class="pl-en">remainingCapacity</span>();

     <span class="pl-c">//删除我们指定的对象，如果成功返回true，反之返回false。</span>
    <span class="pl-smi">boolean</span> <span class="pl-en">remove</span>(<span class="pl-smi">Object</span> <span class="pl-s1">o</span>);

    <span class="pl-c">//判断队列中是否包含指定元素</span>
    <span class="pl-k">public</span> <span class="pl-smi">boolean</span> <span class="pl-en">contains</span>(<span class="pl-smi">Object</span> <span class="pl-s1">o</span>);

     <span class="pl-c">//将队列中的元素全部存到指定的集合中</span>
    <span class="pl-smi">int</span> <span class="pl-en">drainTo</span>(<span class="pl-smi">Collection</span>&lt;? <span class="pl-en">super</span> <span class="pl-smi">E</span>&gt; <span class="pl-s1">c</span>);

    <span class="pl-c">//转移maxElements个元素到集合中</span>
    <span class="pl-smi">int</span> <span class="pl-en">drainTo</span>(<span class="pl-smi">Collection</span>&lt;? <span class="pl-en">super</span> <span class="pl-smi">E</span>&gt; <span class="pl-s1">c</span>, <span class="pl-smi">int</span> <span class="pl-s1">maxElements</span>);
}</pre></div>
<p dir="auto">了解了 <code>BlockingQueue</code> 的常见操作后，我们就知道了 <code>ArrayBlockingQueue</code> 通过继承 <code>BlockingQueue</code> 的方法并实现后，填充到 <code>AbstractQueue</code> 的方法上，由此我们便知道了上文中 <code>AbstractQueue</code> 的 <code>add</code> 方法的 <code>offer</code> 方法是哪里是实现的了。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public boolean add(E e) {
  //AbstractQueue的offer来自下层的ArrayBlockingQueue从BlockingQueue继承并实现的offer方法
  if (offer(e))
      return true;
  else
      throw new IllegalStateException(&quot;Queue full&quot;);
}"><pre><span class="pl-k">public</span> <span class="pl-smi">boolean</span> <span class="pl-en">add</span>(<span class="pl-smi">E</span> <span class="pl-s1">e</span>) {
  <span class="pl-c">//AbstractQueue的offer来自下层的ArrayBlockingQueue从BlockingQueue继承并实现的offer方法</span>
  <span class="pl-k">if</span> (<span class="pl-en">offer</span>(<span class="pl-s1">e</span>))
      <span class="pl-k">return</span> <span class="pl-c1">true</span>;
  <span class="pl-k">else</span>
      <span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-smi">IllegalStateException</span>(<span class="pl-s">"Queue full"</span>);
}</pre></div>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">初始化</h3><a id="user-content-初始化" class="anchor" aria-label="Permalink: 初始化" href="#初始化"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">了解 <code>ArrayBlockingQueue</code> 的细节前，我们不妨先看看其构造函数，了解一下其初始化过程。从源码中我们可以看出 <code>ArrayBlockingQueue</code> 有 3 个构造方法，而最核心的构造方法就是下方这一个。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// capacity 表示队列初始容量，fair 表示 锁的公平性
public ArrayBlockingQueue(int capacity, boolean fair) {
  //如果设置的队列大小小于0，则直接抛出IllegalArgumentException
  if (capacity &lt;= 0)
      throw new IllegalArgumentException();
  //初始化一个数组用于存放队列的元素
  this.items = new Object[capacity];
  //创建阻塞队列流程控制的锁
  lock = new ReentrantLock(fair);
  //用lock锁创建两个条件控制队列生产和消费
  notEmpty = lock.newCondition();
  notFull =  lock.newCondition();
}"><pre><span class="pl-c">// capacity 表示队列初始容量，fair 表示 锁的公平性</span>
<span class="pl-k">public</span> <span class="pl-smi">ArrayBlockingQueue</span><span class="pl-en"></span>(<span class="pl-smi">int</span> <span class="pl-s1">capacity</span>, <span class="pl-smi">boolean</span> <span class="pl-s1">fair</span>) {
  <span class="pl-c">//如果设置的队列大小小于0，则直接抛出IllegalArgumentException</span>
  <span class="pl-k">if</span> (<span class="pl-s1">capacity</span> &lt;= <span class="pl-c1">0</span>)
      <span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-smi">IllegalArgumentException</span>();
  <span class="pl-c">//初始化一个数组用于存放队列的元素</span>
  <span class="pl-smi">this</span>.<span class="pl-s1">items</span> = <span class="pl-k">new</span> <span class="pl-smi">Object</span>[<span class="pl-s1">capacity</span>];
  <span class="pl-c">//创建阻塞队列流程控制的锁</span>
  <span class="pl-s1">lock</span> = <span class="pl-k">new</span> <span class="pl-smi">ReentrantLock</span>(<span class="pl-s1">fair</span>);
  <span class="pl-c">//用lock锁创建两个条件控制队列生产和消费</span>
  <span class="pl-s1">notEmpty</span> = <span class="pl-s1">lock</span>.<span class="pl-en">newCondition</span>();
  <span class="pl-s1">notFull</span> =  <span class="pl-s1">lock</span>.<span class="pl-en">newCondition</span>();
}</pre></div>
<p dir="auto">这个构造方法里面有两个比较核心的成员变量 <code>notEmpty</code>(非空) 和 <code>notFull</code> （非满） ，需要我们格外留意，它们是实现生产者和消费者有序工作的关键所在，这一点笔者会在后续的源码解析中详细说明，这里我们只需初步了解一下阻塞队列的构造即可。</p>
<p dir="auto">另外两个构造方法都是基于上述的构造方法，默认情况下，我们会使用下面这个构造方法，该构造方法就意味着 <code>ArrayBlockingQueue</code> 用的是非公平锁，即各个生产者或者消费者线程收到通知后，对于锁的争抢是随机的。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content=" public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }"><pre> <span class="pl-k">public</span> <span class="pl-smi">ArrayBlockingQueue</span><span class="pl-en"></span>(<span class="pl-smi">int</span> <span class="pl-s1">capacity</span>) {
        <span class="pl-smi">this</span>(<span class="pl-s1">capacity</span>, <span class="pl-s1">false</span>);
    }</pre></div>
<p dir="auto">还有一个不怎么常用的构造方法，在初始化容量和锁的非公平性之后，它还提供了一个 <code>Collection</code> 参数，从源码中不难看出这个构造方法是将外部传入的集合的元素在初始化时直接存放到阻塞队列中。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public ArrayBlockingQueue(int capacity, boolean fair,
                              Collection&lt;? extends E&gt; c) {
  //初始化容量和锁的公平性
  this(capacity, fair);

  final ReentrantLock lock = this.lock;
  //上锁并将c中的元素存放到ArrayBlockingQueue底层的数组中
  lock.lock();
  try {
      int i = 0;
      try {
                //遍历并添加元素到数组中
          for (E e : c) {
              checkNotNull(e);
              items[i++] = e;
          }
      } catch (ArrayIndexOutOfBoundsException ex) {
          throw new IllegalArgumentException();
      }
      //记录当前队列容量
      count = i;
                      //更新下一次put或者offer或用add方法添加到队列底层数组的位置
      putIndex = (i == capacity) ? 0 : i;
  } finally {
      //完成遍历后释放锁
      lock.unlock();
  }
}"><pre><span class="pl-k">public</span> <span class="pl-smi">ArrayBlockingQueue</span><span class="pl-en"></span>(<span class="pl-smi">int</span> <span class="pl-s1">capacity</span>, <span class="pl-smi">boolean</span> <span class="pl-s1">fair</span>,
                              <span class="pl-smi">Collection</span>&lt;? <span class="pl-k">extends</span> <span class="pl-smi">E</span>&gt; <span class="pl-s1">c</span>) {
  <span class="pl-c">//初始化容量和锁的公平性</span>
  <span class="pl-smi">this</span>(<span class="pl-s1">capacity</span>, <span class="pl-s1">fair</span>);

  <span class="pl-k">final</span> <span class="pl-smi">ReentrantLock</span> <span class="pl-s1">lock</span> = <span class="pl-smi">this</span>.<span class="pl-s1">lock</span>;
  <span class="pl-c">//上锁并将c中的元素存放到ArrayBlockingQueue底层的数组中</span>
  <span class="pl-s1">lock</span>.<span class="pl-en">lock</span>();
  <span class="pl-k">try</span> {
      <span class="pl-smi">int</span> <span class="pl-s1">i</span> = <span class="pl-c1">0</span>;
      <span class="pl-k">try</span> {
                <span class="pl-c">//遍历并添加元素到数组中</span>
          <span class="pl-k">for</span> (<span class="pl-smi">E</span> <span class="pl-s1">e</span> : <span class="pl-s1">c</span>) {
              <span class="pl-en">checkNotNull</span>(<span class="pl-s1">e</span>);
              <span class="pl-s1">items</span>[<span class="pl-s1">i</span>++] = <span class="pl-s1">e</span>;
          }
      } <span class="pl-k">catch</span> (<span class="pl-smi">ArrayIndexOutOfBoundsException</span> <span class="pl-s1">ex</span>) {
          <span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-smi">IllegalArgumentException</span>();
      }
      <span class="pl-c">//记录当前队列容量</span>
      <span class="pl-s1">count</span> = <span class="pl-s1">i</span>;
                      <span class="pl-c">//更新下一次put或者offer或用add方法添加到队列底层数组的位置</span>
      <span class="pl-s1">putIndex</span> = (<span class="pl-s1">i</span> == <span class="pl-s1">capacity</span>) ? <span class="pl-c1">0</span> : <span class="pl-s1">i</span>;
  } <span class="pl-k">finally</span> {
      <span class="pl-c">//完成遍历后释放锁</span>
      <span class="pl-s1">lock</span>.<span class="pl-en">unlock</span>();
  }
}</pre></div>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">阻塞式获取和新增元素</h3><a id="user-content-阻塞式获取和新增元素" class="anchor" aria-label="Permalink: 阻塞式获取和新增元素" href="#阻塞式获取和新增元素"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto"><code>ArrayBlockingQueue</code> 阻塞式获取和新增元素对应的就是生产者-消费者模型，虽然它也支持非阻塞式获取和新增元素（例如 <code>poll()</code> 和 <code>offer(E e)</code> 方法，后文会介绍到），但一般不会使用。</p>
<p dir="auto"><code>ArrayBlockingQueue</code> 阻塞式获取和新增元素的方法为：</p>
<ul dir="auto">
<li><code>put(E e)</code>：将元素插入队列中，如果队列已满，则该方法会一直阻塞，直到队列有空间可用或者线程被中断。</li>
<li><code>take()</code> ：获取并移除队列头部的元素，如果队列为空，则该方法会一直阻塞，直到队列非空或者线程被中断。</li>
</ul>
<p dir="auto">这两个方法实现的关键就是在于两个条件对象 <code>notEmpty</code>(非空) 和 <code>notFull</code> （非满），这个我们在上文的构造方法中有提到。</p>
<p dir="auto">接下来笔者就通过两张图让大家了解一下这两个条件是如何在阻塞队列中运用的。</p>
<p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/d9874a7286006d63b247b9bc7c24521c8ff1bff07c80d07b0a6d812ff0a4da7e/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6e6f74456d7074792d74616b652e706e67"><img src="https://camo.githubusercontent.com/d9874a7286006d63b247b9bc7c24521c8ff1bff07c80d07b0a6d812ff0a4da7e/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6e6f74456d7074792d74616b652e706e67" alt="ArrayBlockingQueue 非空条件" data-canonical-src="https://oss.javaguide.cn/github/javaguide/java/collection/ArrayBlockingQueue-notEmpty-take.png" style="max-width: 100%;"></a></p>
<p dir="auto">假设我们的代码消费者先启动，当它发现队列中没有数据，那么非空条件就会将这个线程挂起，即等待条件非空时挂起。然后 CPU 执行权到达生产者，生产者发现队列中可以存放数据，于是将数据存放进去，通知此时条件非空，此时消费者就会被唤醒到队列中使用 <code>take</code> 等方法获取值了。</p>
<p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/5c766e4ce2e633117eb919e921e12a54c4cf128c27bd4c3bdb10c84072ab1c81/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6e6f7446756c6c2d7075742e706e67"><img src="https://camo.githubusercontent.com/5c766e4ce2e633117eb919e921e12a54c4cf128c27bd4c3bdb10c84072ab1c81/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6e6f7446756c6c2d7075742e706e67" alt="ArrayBlockingQueue 非满条件" data-canonical-src="https://oss.javaguide.cn/github/javaguide/java/collection/ArrayBlockingQueue-notFull-put.png" style="max-width: 100%;"></a></p>
<p dir="auto">随后的执行中，生产者生产速度远远大于消费者消费速度，于是生产者将队列塞满后再次尝试将数据存入队列，发现队列已满，于是阻塞队列就将当前线程挂起，等待非满。然后消费者拿着 CPU 执行权进行消费，于是队列可以存放新数据了，发出一个非满的通知，此时挂起的生产者就会等待 CPU 执行权到来时再次尝试将数据存到队列中。</p>
<p dir="auto">简单了解阻塞队列的基于两个条件的交互流程之后，我们不妨看看 <code>put</code> 和 <code>take</code> 方法的源码。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public void put(E e) throws InterruptedException {
    //确保插入的元素不为null
    checkNotNull(e);
    //加锁
    final ReentrantLock lock = this.lock;
    //这里使用lockInterruptibly()方法而不是lock()方法是为了能够响应中断操作，如果在等待获取锁的过程中被打断则该方法会抛出InterruptedException异常。
    lock.lockInterruptibly();
    try {
            //如果count等数组长度则说明队列已满，当前线程将被挂起放到AQS队列中，等待队列非满时插入（非满条件）。
       //在等待期间，锁会被释放，其他线程可以继续对队列进行操作。
        while (count == items.length)
            notFull.await();
           //如果队列可以存放元素，则调用enqueue将元素入队
        enqueue(e);
    } finally {
        //释放锁
        lock.unlock();
    }
}"><pre><span class="pl-k">public</span> <span class="pl-smi">void</span> <span class="pl-en">put</span>(<span class="pl-smi">E</span> <span class="pl-s1">e</span>) <span class="pl-k">throws</span> <span class="pl-smi">InterruptedException</span> {
    <span class="pl-c">//确保插入的元素不为null</span>
    <span class="pl-en">checkNotNull</span>(<span class="pl-s1">e</span>);
    <span class="pl-c">//加锁</span>
    <span class="pl-k">final</span> <span class="pl-smi">ReentrantLock</span> <span class="pl-s1">lock</span> = <span class="pl-smi">this</span>.<span class="pl-s1">lock</span>;
    <span class="pl-c">//这里使用lockInterruptibly()方法而不是lock()方法是为了能够响应中断操作，如果在等待获取锁的过程中被打断则该方法会抛出InterruptedException异常。</span>
    <span class="pl-s1">lock</span>.<span class="pl-en">lockInterruptibly</span>();
    <span class="pl-k">try</span> {
            <span class="pl-c">//如果count等数组长度则说明队列已满，当前线程将被挂起放到AQS队列中，等待队列非满时插入（非满条件）。</span>
       <span class="pl-c">//在等待期间，锁会被释放，其他线程可以继续对队列进行操作。</span>
        <span class="pl-k">while</span> (<span class="pl-s1">count</span> == <span class="pl-s1">items</span>.<span class="pl-s1">length</span>)
            <span class="pl-s1">notFull</span>.<span class="pl-en">await</span>();
           <span class="pl-c">//如果队列可以存放元素，则调用enqueue将元素入队</span>
        <span class="pl-en">enqueue</span>(<span class="pl-s1">e</span>);
    } <span class="pl-k">finally</span> {
        <span class="pl-c">//释放锁</span>
        <span class="pl-s1">lock</span>.<span class="pl-en">unlock</span>();
    }
}</pre></div>
<p dir="auto"><code>put</code>方法内部调用了 <code>enqueue</code> 方法来实现元素入队，我们继续深入查看一下 <code>enqueue</code> 方法的实现细节：</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="private void enqueue(E x) {
   //获取队列底层的数组
    final Object[] items = this.items;
    //将putindex位置的值设置为我们传入的x
    items[putIndex] = x;
    //更新putindex，如果putindex等于数组长度，则更新为0
    if (++putIndex == items.length)
        putIndex = 0;
    //队列长度+1
    count++;
    //通知队列非空，那些因为获取元素而阻塞的线程可以继续工作了
    notEmpty.signal();
}"><pre><span class="pl-k">private</span> <span class="pl-smi">void</span> <span class="pl-en">enqueue</span>(<span class="pl-smi">E</span> <span class="pl-s1">x</span>) {
   <span class="pl-c">//获取队列底层的数组</span>
    <span class="pl-k">final</span> <span class="pl-smi">Object</span>[] <span class="pl-s1">items</span> = <span class="pl-smi">this</span>.<span class="pl-s1">items</span>;
    <span class="pl-c">//将putindex位置的值设置为我们传入的x</span>
    <span class="pl-s1">items</span>[<span class="pl-s1">putIndex</span>] = <span class="pl-s1">x</span>;
    <span class="pl-c">//更新putindex，如果putindex等于数组长度，则更新为0</span>
    <span class="pl-k">if</span> (++<span class="pl-s1">putIndex</span> == <span class="pl-s1">items</span>.<span class="pl-s1">length</span>)
        <span class="pl-s1">putIndex</span> = <span class="pl-c1">0</span>;
    <span class="pl-c">//队列长度+1</span>
    <span class="pl-s1">count</span>++;
    <span class="pl-c">//通知队列非空，那些因为获取元素而阻塞的线程可以继续工作了</span>
    <span class="pl-s1">notEmpty</span>.<span class="pl-en">signal</span>();
}</pre></div>
<p dir="auto">从源码中可以看到入队操作的逻辑就是在数组中追加一个新元素，整体执行步骤为:</p>
<ol dir="auto">
<li>获取 <code>ArrayBlockingQueue</code> 底层的数组 <code>items</code>。</li>
<li>将元素存到 <code>putIndex</code> 位置。</li>
<li>更新 <code>putIndex</code> 到下一个位置，如果 <code>putIndex</code> 等于队列长度，则说明 <code>putIndex</code> 已经到达数组末尾了，下一次插入则需要 0 开始。(<code>ArrayBlockingQueue</code> 用到了循环队列的思想，即从头到尾循环复用一个数组)</li>
<li>更新 <code>count</code> 的值，表示当前队列长度+1。</li>
<li>调用 <code>notEmpty.signal()</code> 通知队列非空，消费者可以从队列中获取值了。</li>
</ol>
<p dir="auto">自此我们了解了 <code>put</code> 方法的流程，为了更加完整的了解 <code>ArrayBlockingQueue</code> 关于生产者-消费者模型的设计，我们继续看看阻塞获取队列元素的 <code>take</code> 方法。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public E take() throws InterruptedException {
       //获取锁
     final ReentrantLock lock = this.lock;
     lock.lockInterruptibly();
     try {
             //如果队列中元素个数为0，则将当前线程打断并存入AQS队列中，等待队列非空时获取并移除元素（非空条件）
         while (count == 0)
             notEmpty.await();
            //如果队列不为空则调用dequeue获取元素
         return dequeue();
     } finally {
          //释放锁
         lock.unlock();
     }
}"><pre><span class="pl-k">public</span> <span class="pl-smi">E</span> <span class="pl-en">take</span>() <span class="pl-k">throws</span> <span class="pl-smi">InterruptedException</span> {
       <span class="pl-c">//获取锁</span>
     <span class="pl-k">final</span> <span class="pl-smi">ReentrantLock</span> <span class="pl-s1">lock</span> = <span class="pl-smi">this</span>.<span class="pl-s1">lock</span>;
     <span class="pl-s1">lock</span>.<span class="pl-en">lockInterruptibly</span>();
     <span class="pl-k">try</span> {
             <span class="pl-c">//如果队列中元素个数为0，则将当前线程打断并存入AQS队列中，等待队列非空时获取并移除元素（非空条件）</span>
         <span class="pl-k">while</span> (<span class="pl-s1">count</span> == <span class="pl-c1">0</span>)
             <span class="pl-s1">notEmpty</span>.<span class="pl-en">await</span>();
            <span class="pl-c">//如果队列不为空则调用dequeue获取元素</span>
         <span class="pl-k">return</span> <span class="pl-en">dequeue</span>();
     } <span class="pl-k">finally</span> {
          <span class="pl-c">//释放锁</span>
         <span class="pl-s1">lock</span>.<span class="pl-en">unlock</span>();
     }
}</pre></div>
<p dir="auto">理解了 <code>put</code> 方法再看<code>take</code> 方法就很简单了，其核心逻辑和<code>put</code> 方法正好是相反的，比如<code>put</code> 方法在队列满的时候等待队列非满时插入元素（非满条件），而<code>take</code> 方法等待队列非空时获取并移除元素（非空条件）。</p>
<p dir="auto"><code>take</code>方法内部调用了 <code>dequeue</code> 方法来实现元素出队，其核心逻辑和 <code>enqueue</code> 方法也是相反的。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="private E dequeue() {
  //获取阻塞队列底层的数组
  final Object[] items = this.items;
  @SuppressWarnings(&quot;unchecked&quot;)
  //从队列中获取takeIndex位置的元素
  E x = (E) items[takeIndex];
  //将takeIndex置空
  items[takeIndex] = null;
  //takeIndex向后挪动，如果等于数组长度则更新为0
  if (++takeIndex == items.length)
      takeIndex = 0;
  //队列长度减1
  count--;
  if (itrs != null)
      itrs.elementDequeued();
  //通知那些被打断的线程当前队列状态非满，可以继续存放元素
  notFull.signal();
  return x;
}"><pre><span class="pl-k">private</span> <span class="pl-smi">E</span> <span class="pl-en">dequeue</span>() {
  <span class="pl-c">//获取阻塞队列底层的数组</span>
  <span class="pl-k">final</span> <span class="pl-smi">Object</span>[] <span class="pl-s1">items</span> = <span class="pl-smi">this</span>.<span class="pl-s1">items</span>;
  <span class="pl-c1">@</span><span class="pl-c1">SuppressWarnings</span>(<span class="pl-s">"unchecked"</span>)
  <span class="pl-c">//从队列中获取takeIndex位置的元素</span>
  <span class="pl-smi">E</span> <span class="pl-s1">x</span> = (<span class="pl-smi">E</span>) <span class="pl-s1">items</span>[<span class="pl-s1">takeIndex</span>];
  <span class="pl-c">//将takeIndex置空</span>
  <span class="pl-s1">items</span>[<span class="pl-s1">takeIndex</span>] = <span class="pl-c1">null</span>;
  <span class="pl-c">//takeIndex向后挪动，如果等于数组长度则更新为0</span>
  <span class="pl-k">if</span> (++<span class="pl-s1">takeIndex</span> == <span class="pl-s1">items</span>.<span class="pl-s1">length</span>)
      <span class="pl-s1">takeIndex</span> = <span class="pl-c1">0</span>;
  <span class="pl-c">//队列长度减1</span>
  <span class="pl-s1">count</span>--;
  <span class="pl-k">if</span> (<span class="pl-s1">itrs</span> != <span class="pl-c1">null</span>)
      <span class="pl-s1">itrs</span>.<span class="pl-en">elementDequeued</span>();
  <span class="pl-c">//通知那些被打断的线程当前队列状态非满，可以继续存放元素</span>
  <span class="pl-s1">notFull</span>.<span class="pl-en">signal</span>();
  <span class="pl-k">return</span> <span class="pl-s1">x</span>;
}</pre></div>
<p dir="auto">由于<code>dequeue</code> 方法（出队）和上面介绍的 <code>enqueue</code> 方法（入队）的步骤大致类似，这里就不重复介绍了。</p>
<p dir="auto">为了帮助理解，我专门画了一张图来展示 <code>notEmpty</code>(非空) 和 <code>notFull</code> （非满）这两个条件对象是如何控制 <code>ArrayBlockingQueue</code> 的存和取的。</p>
<p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/999005dccc8278ce18e7c2ade8b47cfbc4c5f2faac946c11aa3329617015ebb5/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6e6f74456d7074792d6e6f7446756c6c2e706e67"><img src="https://camo.githubusercontent.com/999005dccc8278ce18e7c2ade8b47cfbc4c5f2faac946c11aa3329617015ebb5/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6e6f74456d7074792d6e6f7446756c6c2e706e67" alt="ArrayBlockingQueue 非空非满" data-canonical-src="https://oss.javaguide.cn/github/javaguide/java/collection/ArrayBlockingQueue-notEmpty-notFull.png" style="max-width: 100%;"></a></p>
<ul dir="auto">
<li><strong>消费者</strong>：当消费者从队列中 <code>take</code> 或者 <code>poll</code> 等操作取出一个元素之后，就会通知队列非满，此时那些等待非满的生产者就会被唤醒等待获取 CPU 时间片进行入队操作。</li>
<li><strong>生产者</strong>：当生产者将元素存到队列中后，就会触发通知队列非空，此时消费者就会被唤醒等待 CPU 时间片尝试获取元素。如此往复，两个条件对象就构成一个环路，控制着多线程之间的存和取。</li>
</ul>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">非阻塞式获取和新增元素</h3><a id="user-content-非阻塞式获取和新增元素" class="anchor" aria-label="Permalink: 非阻塞式获取和新增元素" href="#非阻塞式获取和新增元素"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto"><code>ArrayBlockingQueue</code> 非阻塞式获取和新增元素的方法为：</p>
<ul dir="auto">
<li><code>offer(E e)</code>：将元素插入队列尾部。如果队列已满，则该方法会直接返回 false，不会等待并阻塞线程。</li>
<li><code>poll()</code>：获取并移除队列头部的元素，如果队列为空，则该方法会直接返回 null，不会等待并阻塞线程。</li>
<li><code>add(E e)</code>：将元素插入队列尾部。如果队列已满则会抛出 <code>IllegalStateException</code> 异常，底层基于 <code>offer(E e)</code> 方法。</li>
<li><code>remove()</code>：移除队列头部的元素，如果队列为空则会抛出 <code>NoSuchElementException</code> 异常，底层基于 <code>poll()</code>。</li>
<li><code>peek()</code>：获取但不移除队列头部的元素，如果队列为空，则该方法会直接返回 null，不会等待并阻塞线程。</li>
</ul>
<p dir="auto">先来看看 <code>offer</code> 方法，逻辑和 <code>put</code> 差不多，唯一的区别就是入队失败时不会阻塞当前线程，而是直接返回 <code>false</code>。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public boolean offer(E e) {
        //确保插入的元素不为null
        checkNotNull(e);
        //获取锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
             //队列已满直接返回false
            if (count == items.length)
                return false;
            else {
                //反之将元素入队并直接返回true
                enqueue(e);
                return true;
            }
        } finally {
            //释放锁
            lock.unlock();
        }
    }"><pre><span class="pl-k">public</span> <span class="pl-smi">boolean</span> <span class="pl-en">offer</span>(<span class="pl-smi">E</span> <span class="pl-s1">e</span>) {
        <span class="pl-c">//确保插入的元素不为null</span>
        <span class="pl-en">checkNotNull</span>(<span class="pl-s1">e</span>);
        <span class="pl-c">//获取锁</span>
        <span class="pl-k">final</span> <span class="pl-smi">ReentrantLock</span> <span class="pl-s1">lock</span> = <span class="pl-smi">this</span>.<span class="pl-s1">lock</span>;
        <span class="pl-s1">lock</span>.<span class="pl-en">lock</span>();
        <span class="pl-k">try</span> {
             <span class="pl-c">//队列已满直接返回false</span>
            <span class="pl-k">if</span> (<span class="pl-s1">count</span> == <span class="pl-s1">items</span>.<span class="pl-s1">length</span>)
                <span class="pl-k">return</span> <span class="pl-c1">false</span>;
            <span class="pl-k">else</span> {
                <span class="pl-c">//反之将元素入队并直接返回true</span>
                <span class="pl-en">enqueue</span>(<span class="pl-s1">e</span>);
                <span class="pl-k">return</span> <span class="pl-c1">true</span>;
            }
        } <span class="pl-k">finally</span> {
            <span class="pl-c">//释放锁</span>
            <span class="pl-s1">lock</span>.<span class="pl-en">unlock</span>();
        }
    }</pre></div>
<p dir="auto"><code>poll</code> 方法同理，获取元素失败也是直接返回空，并不会阻塞获取元素的线程。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public E poll() {
        final ReentrantLock lock = this.lock;
        //上锁
        lock.lock();
        try {
            //如果队列为空直接返回null，反之出队返回元素值
            return (count == 0) ? null : dequeue();
        } finally {
            lock.unlock();
        }
    }"><pre><span class="pl-k">public</span> <span class="pl-smi">E</span> <span class="pl-en">poll</span>() {
        <span class="pl-k">final</span> <span class="pl-smi">ReentrantLock</span> <span class="pl-s1">lock</span> = <span class="pl-smi">this</span>.<span class="pl-s1">lock</span>;
        <span class="pl-c">//上锁</span>
        <span class="pl-s1">lock</span>.<span class="pl-en">lock</span>();
        <span class="pl-k">try</span> {
            <span class="pl-c">//如果队列为空直接返回null，反之出队返回元素值</span>
            <span class="pl-k">return</span> (<span class="pl-s1">count</span> == <span class="pl-c1">0</span>) ? <span class="pl-c1">null</span> : <span class="pl-en">dequeue</span>();
        } <span class="pl-k">finally</span> {
            <span class="pl-s1">lock</span>.<span class="pl-en">unlock</span>();
        }
    }</pre></div>
<p dir="auto"><code>add</code> 方法其实就是对于 <code>offer</code> 做了一层封装，如下代码所示，可以看到 <code>add</code> 会调用没有规定时间的 <code>offer</code>，如果入队失败则直接抛异常。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public boolean add(E e) {
        return super.add(e);
    }


public boolean add(E e) {
        //调用offer方法如果失败直接抛出异常
        if (offer(e))
            return true;
        else
            throw new IllegalStateException(&quot;Queue full&quot;);
    }"><pre><span class="pl-k">public</span> <span class="pl-smi">boolean</span> <span class="pl-en">add</span>(<span class="pl-smi">E</span> <span class="pl-s1">e</span>) {
        <span class="pl-k">return</span> <span class="pl-en">super</span>.<span class="pl-en">add</span>(<span class="pl-s1">e</span>);
    }


<span class="pl-k">public</span> <span class="pl-smi">boolean</span> <span class="pl-en">add</span>(<span class="pl-smi">E</span> <span class="pl-s1">e</span>) {
        <span class="pl-c">//调用offer方法如果失败直接抛出异常</span>
        <span class="pl-k">if</span> (<span class="pl-en">offer</span>(<span class="pl-s1">e</span>))
            <span class="pl-k">return</span> <span class="pl-c1">true</span>;
        <span class="pl-k">else</span>
            <span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-smi">IllegalStateException</span>(<span class="pl-s">"Queue full"</span>);
    }</pre></div>
<p dir="auto"><code>remove</code> 方法同理，调用 <code>poll</code>，如果返回 <code>null</code> 则说明队列没有元素，直接抛出异常。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public E remove() {
        E x = poll();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }"><pre><span class="pl-k">public</span> <span class="pl-smi">E</span> <span class="pl-en">remove</span>() {
        <span class="pl-smi">E</span> <span class="pl-s1">x</span> = <span class="pl-en">poll</span>();
        <span class="pl-k">if</span> (<span class="pl-s1">x</span> != <span class="pl-c1">null</span>)
            <span class="pl-k">return</span> <span class="pl-s1">x</span>;
        <span class="pl-k">else</span>
            <span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-smi">NoSuchElementException</span>();
    }</pre></div>
<p dir="auto"><code>peek()</code> 方法的逻辑也很简单，内部调用了 <code>itemAt</code> 方法。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public E peek() {
        //加锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //当队列为空时返回 null
            return itemAt(takeIndex);
        } finally {
            //释放锁
            lock.unlock();
        }
    }

//返回队列中指定位置的元素
@SuppressWarnings(&quot;unchecked&quot;)
final E itemAt(int i) {
    return (E) items[i];
}"><pre><span class="pl-k">public</span> <span class="pl-smi">E</span> <span class="pl-en">peek</span>() {
        <span class="pl-c">//加锁</span>
        <span class="pl-k">final</span> <span class="pl-smi">ReentrantLock</span> <span class="pl-s1">lock</span> = <span class="pl-smi">this</span>.<span class="pl-s1">lock</span>;
        <span class="pl-s1">lock</span>.<span class="pl-en">lock</span>();
        <span class="pl-k">try</span> {
            <span class="pl-c">//当队列为空时返回 null</span>
            <span class="pl-k">return</span> <span class="pl-en">itemAt</span>(<span class="pl-s1">takeIndex</span>);
        } <span class="pl-k">finally</span> {
            <span class="pl-c">//释放锁</span>
            <span class="pl-s1">lock</span>.<span class="pl-en">unlock</span>();
        }
    }

<span class="pl-c">//返回队列中指定位置的元素</span>
<span class="pl-c1">@</span><span class="pl-c1">SuppressWarnings</span>(<span class="pl-s">"unchecked"</span>)
<span class="pl-k">final</span> <span class="pl-smi">E</span> <span class="pl-en">itemAt</span>(<span class="pl-smi">int</span> <span class="pl-s1">i</span>) {
    <span class="pl-k">return</span> (<span class="pl-smi">E</span>) <span class="pl-s1">items</span>[<span class="pl-s1">i</span>];
}</pre></div>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">指定超时时间内阻塞式获取和新增元素</h3><a id="user-content-指定超时时间内阻塞式获取和新增元素" class="anchor" aria-label="Permalink: 指定超时时间内阻塞式获取和新增元素" href="#指定超时时间内阻塞式获取和新增元素"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">在 <code>offer(E e)</code> 和 <code>poll()</code> 非阻塞获取和新增元素的基础上，设计者提供了带有等待时间的 <code>offer(E e, long timeout, TimeUnit unit)</code> 和 <code>poll(long timeout, TimeUnit unit)</code> ，用于在指定的超时时间内阻塞式地添加和获取元素。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content=" public boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException {

        checkNotNull(e);
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
        //队列已满，进入循环
            while (count == items.length) {
            //时间到了队列还是满的，则直接返回false
                if (nanos &lt;= 0)
                    return false;
                 //阻塞nanos时间，等待非满
                nanos = notFull.awaitNanos(nanos);
            }
            enqueue(e);
            return true;
        } finally {
            lock.unlock();
        }
    }"><pre> <span class="pl-k">public</span> <span class="pl-smi">boolean</span> <span class="pl-en">offer</span>(<span class="pl-smi">E</span> <span class="pl-s1">e</span>, <span class="pl-smi">long</span> <span class="pl-s1">timeout</span>, <span class="pl-smi">TimeUnit</span> <span class="pl-s1">unit</span>)
        <span class="pl-k">throws</span> <span class="pl-smi">InterruptedException</span> {

        <span class="pl-en">checkNotNull</span>(<span class="pl-s1">e</span>);
        <span class="pl-smi">long</span> <span class="pl-s1">nanos</span> = <span class="pl-s1">unit</span>.<span class="pl-en">toNanos</span>(<span class="pl-s1">timeout</span>);
        <span class="pl-k">final</span> <span class="pl-smi">ReentrantLock</span> <span class="pl-s1">lock</span> = <span class="pl-smi">this</span>.<span class="pl-s1">lock</span>;
        <span class="pl-s1">lock</span>.<span class="pl-en">lockInterruptibly</span>();
        <span class="pl-k">try</span> {
        <span class="pl-c">//队列已满，进入循环</span>
            <span class="pl-k">while</span> (<span class="pl-s1">count</span> == <span class="pl-s1">items</span>.<span class="pl-s1">length</span>) {
            <span class="pl-c">//时间到了队列还是满的，则直接返回false</span>
                <span class="pl-k">if</span> (<span class="pl-s1">nanos</span> &lt;= <span class="pl-c1">0</span>)
                    <span class="pl-k">return</span> <span class="pl-c1">false</span>;
                 <span class="pl-c">//阻塞nanos时间，等待非满</span>
                <span class="pl-s1">nanos</span> = <span class="pl-s1">notFull</span>.<span class="pl-en">awaitNanos</span>(<span class="pl-s1">nanos</span>);
            }
            <span class="pl-en">enqueue</span>(<span class="pl-s1">e</span>);
            <span class="pl-k">return</span> <span class="pl-c1">true</span>;
        } <span class="pl-k">finally</span> {
            <span class="pl-s1">lock</span>.<span class="pl-en">unlock</span>();
        }
    }</pre></div>
<p dir="auto">可以看到，带有超时时间的 <code>offer</code> 方法在队列已满的情况下，会等待用户所传的时间段，如果规定时间内还不能存放元素则直接返回 <code>false</code>。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
          //队列为空，循环等待，若时间到还是空的，则直接返回null
            while (count == 0) {
                if (nanos &lt;= 0)
                    return null;
                nanos = notEmpty.awaitNanos(nanos);
            }
            return dequeue();
        } finally {
            lock.unlock();
        }
    }"><pre><span class="pl-k">public</span> <span class="pl-smi">E</span> <span class="pl-en">poll</span>(<span class="pl-smi">long</span> <span class="pl-s1">timeout</span>, <span class="pl-smi">TimeUnit</span> <span class="pl-s1">unit</span>) <span class="pl-k">throws</span> <span class="pl-smi">InterruptedException</span> {
        <span class="pl-smi">long</span> <span class="pl-s1">nanos</span> = <span class="pl-s1">unit</span>.<span class="pl-en">toNanos</span>(<span class="pl-s1">timeout</span>);
        <span class="pl-k">final</span> <span class="pl-smi">ReentrantLock</span> <span class="pl-s1">lock</span> = <span class="pl-smi">this</span>.<span class="pl-s1">lock</span>;
        <span class="pl-s1">lock</span>.<span class="pl-en">lockInterruptibly</span>();
        <span class="pl-k">try</span> {
          <span class="pl-c">//队列为空，循环等待，若时间到还是空的，则直接返回null</span>
            <span class="pl-k">while</span> (<span class="pl-s1">count</span> == <span class="pl-c1">0</span>) {
                <span class="pl-k">if</span> (<span class="pl-s1">nanos</span> &lt;= <span class="pl-c1">0</span>)
                    <span class="pl-k">return</span> <span class="pl-c1">null</span>;
                <span class="pl-s1">nanos</span> = <span class="pl-s1">notEmpty</span>.<span class="pl-en">awaitNanos</span>(<span class="pl-s1">nanos</span>);
            }
            <span class="pl-k">return</span> <span class="pl-en">dequeue</span>();
        } <span class="pl-k">finally</span> {
            <span class="pl-s1">lock</span>.<span class="pl-en">unlock</span>();
        }
    }</pre></div>
<p dir="auto">同理，带有超时时间的 <code>poll</code> 也一样，队列为空则在规定时间内等待，若时间到了还是空的，则直接返回 null。</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">判断元素是否存在</h3><a id="user-content-判断元素是否存在" class="anchor" aria-label="Permalink: 判断元素是否存在" href="#判断元素是否存在"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto"><code>ArrayBlockingQueue</code> 提供了 <code>contains(Object o)</code> 来判断指定元素是否存在于队列中。</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="public boolean contains(Object o) {
    //若目标元素为空，则直接返回 false
    if (o == null) return false;
    //获取当前队列的元素数组
    final Object[] items = this.items;
    //加锁
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        // 如果队列非空
        if (count &gt; 0) {
            final int putIndex = this.putIndex;
            //从队列头部开始遍历
            int i = takeIndex;
            do {
                if (o.equals(items[i]))
                    return true;
                if (++i == items.length)
                    i = 0;
            } while (i != putIndex);
        }
        return false;
    } finally {
        //释放锁
        lock.unlock();
    }
}"><pre><span class="pl-k">public</span> <span class="pl-smi">boolean</span> <span class="pl-en">contains</span>(<span class="pl-smi">Object</span> <span class="pl-s1">o</span>) {
    <span class="pl-c">//若目标元素为空，则直接返回 false</span>
    <span class="pl-k">if</span> (<span class="pl-s1">o</span> == <span class="pl-c1">null</span>) <span class="pl-k">return</span> <span class="pl-c1">false</span>;
    <span class="pl-c">//获取当前队列的元素数组</span>
    <span class="pl-k">final</span> <span class="pl-smi">Object</span>[] <span class="pl-s1">items</span> = <span class="pl-smi">this</span>.<span class="pl-s1">items</span>;
    <span class="pl-c">//加锁</span>
    <span class="pl-k">final</span> <span class="pl-smi">ReentrantLock</span> <span class="pl-s1">lock</span> = <span class="pl-smi">this</span>.<span class="pl-s1">lock</span>;
    <span class="pl-s1">lock</span>.<span class="pl-en">lock</span>();
    <span class="pl-k">try</span> {
        <span class="pl-c">// 如果队列非空</span>
        <span class="pl-k">if</span> (<span class="pl-s1">count</span> &gt; <span class="pl-c1">0</span>) {
            <span class="pl-k">final</span> <span class="pl-smi">int</span> <span class="pl-s1">putIndex</span> = <span class="pl-smi">this</span>.<span class="pl-s1">putIndex</span>;
            <span class="pl-c">//从队列头部开始遍历</span>
            <span class="pl-smi">int</span> <span class="pl-s1">i</span> = <span class="pl-s1">takeIndex</span>;
            <span class="pl-k">do</span> {
                <span class="pl-k">if</span> (<span class="pl-s1">o</span>.<span class="pl-en">equals</span>(<span class="pl-s1">items</span>[<span class="pl-s1">i</span>]))
                    <span class="pl-k">return</span> <span class="pl-c1">true</span>;
                <span class="pl-k">if</span> (++<span class="pl-s1">i</span> == <span class="pl-s1">items</span>.<span class="pl-s1">length</span>)
                    <span class="pl-s1">i</span> = <span class="pl-c1">0</span>;
            } <span class="pl-k">while</span> (<span class="pl-s1">i</span> != <span class="pl-s1">putIndex</span>);
        }
        <span class="pl-k">return</span> <span class="pl-c1">false</span>;
    } <span class="pl-k">finally</span> {
        <span class="pl-c">//释放锁</span>
        <span class="pl-s1">lock</span>.<span class="pl-en">unlock</span>();
    }
}</pre></div>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">ArrayBlockingQueue 获取和新增元素的方法对比</h2><a id="user-content-arrayblockingqueue-获取和新增元素的方法对比" class="anchor" aria-label="Permalink: ArrayBlockingQueue 获取和新增元素的方法对比" href="#arrayblockingqueue-获取和新增元素的方法对比"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto">为了帮助理解 <code>ArrayBlockingQueue</code> ，我们再来对比一下上面提到的这些获取和新增元素的方法。</p>
<p dir="auto">新增元素：</p>
<markdown-accessiblity-table><table>
<thead>
<tr>
<th>方法</th>
<th>队列满时处理方式</th>
<th>方法返回值</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>put(E e)</code></td>
<td>线程阻塞，直到中断或被唤醒</td>
<td>void</td>
</tr>
<tr>
<td><code>offer(E e)</code></td>
<td>直接返回 false</td>
<td>boolean</td>
</tr>
<tr>
<td><code>offer(E e, long timeout, TimeUnit unit)</code></td>
<td>指定超时时间内阻塞，超过规定时间还未添加成功则返回 false</td>
<td>boolean</td>
</tr>
<tr>
<td><code>add(E e)</code></td>
<td>直接抛出 <code>IllegalStateException</code> 异常</td>
<td>boolean</td>
</tr>
</tbody>
</table></markdown-accessiblity-table>
<p dir="auto">获取/移除元素：</p>
<markdown-accessiblity-table><table>
<thead>
<tr>
<th>方法</th>
<th>队列空时处理方式</th>
<th>方法返回值</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>take()</code></td>
<td>线程阻塞，直到中断或被唤醒</td>
<td>E</td>
</tr>
<tr>
<td><code>poll()</code></td>
<td>返回 null</td>
<td>E</td>
</tr>
<tr>
<td><code>poll(long timeout, TimeUnit unit)</code></td>
<td>指定超时时间内阻塞，超过规定时间还是空的则返回 null</td>
<td>E</td>
</tr>
<tr>
<td><code>peek()</code></td>
<td>返回 null</td>
<td>E</td>
</tr>
<tr>
<td><code>remove()</code></td>
<td>直接抛出 <code>NoSuchElementException</code> 异常</td>
<td>boolean</td>
</tr>
</tbody>
</table></markdown-accessiblity-table>
<p dir="auto"><a target="_blank" rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/09b66774ef1ad6fdfeec1b3e178474d1a33222fb85e3f399026d4e4a5f79f1cc/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6765742d6164642d656c656d656e742d6d6574686f64732e706e67"><img src="https://camo.githubusercontent.com/09b66774ef1ad6fdfeec1b3e178474d1a33222fb85e3f399026d4e4a5f79f1cc/68747470733a2f2f6f73732e6a61766167756964652e636e2f6769746875622f6a61766167756964652f6a6176612f636f6c6c656374696f6e2f4172726179426c6f636b696e6751756575652d6765742d6164642d656c656d656e742d6d6574686f64732e706e67" alt="" data-canonical-src="https://oss.javaguide.cn/github/javaguide/java/collection/ArrayBlockingQueue-get-add-element-methods.png" style="max-width: 100%;"></a></p>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">ArrayBlockingQueue 相关面试题</h2><a id="user-content-arrayblockingqueue-相关面试题" class="anchor" aria-label="Permalink: ArrayBlockingQueue 相关面试题" href="#arrayblockingqueue-相关面试题"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">ArrayBlockingQueue 是什么？它的特点是什么？</h3><a id="user-content-arrayblockingqueue-是什么它的特点是什么" class="anchor" aria-label="Permalink: ArrayBlockingQueue 是什么？它的特点是什么？" href="#arrayblockingqueue-是什么它的特点是什么"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto"><code>ArrayBlockingQueue</code> 是 <code>BlockingQueue</code> 接口的有界队列实现类，常用于多线程之间的数据共享，底层采用数组实现，从其名字就能看出来了。</p>
<p dir="auto"><code>ArrayBlockingQueue</code> 的容量有限，一旦创建，容量不能改变。</p>
<p dir="auto">为了保证线程安全，<code>ArrayBlockingQueue</code> 的并发控制采用可重入锁 <code>ReentrantLock</code> ，不管是插入操作还是读取操作，都需要获取到锁才能进行操作。并且，它还支持公平和非公平两种方式的锁访问机制，默认是非公平锁。</p>
<p dir="auto"><code>ArrayBlockingQueue</code> 虽名为阻塞队列，但也支持非阻塞获取和新增元素（例如 <code>poll()</code> 和 <code>offer(E e)</code> 方法），只是队列满时添加元素会抛出异常，队列为空时获取的元素为 null，一般不会使用。</p>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别？</h3><a id="user-content-arrayblockingqueue-和-linkedblockingqueue-有什么区别" class="anchor" aria-label="Permalink: ArrayBlockingQueue 和 LinkedBlockingQueue 有什么区别？" href="#arrayblockingqueue-和-linkedblockingqueue-有什么区别"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto"><code>ArrayBlockingQueue</code> 和 <code>LinkedBlockingQueue</code> 是 Java 并发包中常用的两种阻塞队列实现，它们都是线程安全的。不过，不过它们之间也存在下面这些区别：</p>
<ul dir="auto">
<li>底层实现：<code>ArrayBlockingQueue</code> 基于数组实现，而 <code>LinkedBlockingQueue</code> 基于链表实现。</li>
<li>是否有界：<code>ArrayBlockingQueue</code> 是有界队列，必须在创建时指定容量大小。<code>LinkedBlockingQueue</code> 创建时可以不指定容量大小，默认是<code>Integer.MAX_VALUE</code>，也就是无界的。但也可以指定队列大小，从而成为有界的。</li>
<li>锁是否分离： <code>ArrayBlockingQueue</code>中的锁是没有分离的，即生产和消费用的是同一个锁；<code>LinkedBlockingQueue</code>中的锁是分离的，即生产用的是<code>putLock</code>，消费是<code>takeLock</code>，这样可以防止生产者和消费者线程之间的锁争夺。</li>
<li>内存占用：<code>ArrayBlockingQueue</code> 需要提前分配数组内存，而 <code>LinkedBlockingQueue</code> 则是动态分配链表节点内存。这意味着，<code>ArrayBlockingQueue</code> 在创建时就会占用一定的内存空间，且往往申请的内存比实际所用的内存更大，而<code>LinkedBlockingQueue</code> 则是根据元素的增加而逐渐占用内存空间。</li>
</ul>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">ArrayBlockingQueue 和 ConcurrentLinkedQueue 有什么区别？</h3><a id="user-content-arrayblockingqueue-和-concurrentlinkedqueue-有什么区别" class="anchor" aria-label="Permalink: ArrayBlockingQueue 和 ConcurrentLinkedQueue 有什么区别？" href="#arrayblockingqueue-和-concurrentlinkedqueue-有什么区别"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto"><code>ArrayBlockingQueue</code> 和 <code>ConcurrentLinkedQueue</code> 是 Java 并发包中常用的两种队列实现，它们都是线程安全的。不过，不过它们之间也存在下面这些区别：</p>
<ul dir="auto">
<li>底层实现：<code>ArrayBlockingQueue</code> 基于数组实现，而 <code>ConcurrentLinkedQueue</code> 基于链表实现。</li>
<li>是否有界：<code>ArrayBlockingQueue</code> 是有界队列，必须在创建时指定容量大小，而 <code>ConcurrentLinkedQueue</code> 是无界队列，可以动态地增加容量。</li>
<li>是否阻塞：<code>ArrayBlockingQueue</code> 支持阻塞和非阻塞两种获取和新增元素的方式（一般只会使用前者）， <code>ConcurrentLinkedQueue</code> 是无界的，仅支持非阻塞式获取和新增元素。</li>
</ul>
<div class="markdown-heading" dir="auto"><h3 tabindex="-1" class="heading-element" dir="auto">ArrayBlockingQueue 的实现原理是什么？</h3><a id="user-content-arrayblockingqueue-的实现原理是什么" class="anchor" aria-label="Permalink: ArrayBlockingQueue 的实现原理是什么？" href="#arrayblockingqueue-的实现原理是什么"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p dir="auto"><code>ArrayBlockingQueue</code> 的实现原理主要分为以下几点（这里以阻塞式获取和新增元素为例介绍）：</p>
<ul dir="auto">
<li><code>ArrayBlockingQueue</code> 内部维护一个定长的数组用于存储元素。</li>
<li>通过使用 <code>ReentrantLock</code> 锁对象对读写操作进行同步，即通过锁机制来实现线程安全。</li>
<li>通过 <code>Condition</code> 实现线程间的等待和唤醒操作。</li>
</ul>
<p dir="auto">这里再详细介绍一下线程间的等待和唤醒具体的实现（不需要记具体的方法，面试中回答要点即可）：</p>
<ul dir="auto">
<li>当队列已满时，生产者线程会调用 <code>notFull.await()</code> 方法让生产者进行等待，等待队列非满时插入（非满条件）。</li>
<li>当队列为空时，消费者线程会调用 <code>notEmpty.await()</code>方法让消费者进行等待，等待队列非空时消费（非空条件）。</li>
<li>当有新的元素被添加时，生产者线程会调用 <code>notEmpty.signal()</code>方法唤醒正在等待消费的消费者线程。</li>
<li>当队列中有元素被取出时，消费者线程会调用 <code>notFull.signal()</code>方法唤醒正在等待插入元素的生产者线程。</li>
</ul>
<p dir="auto">关于 <code>Condition</code>接口的补充：</p>
<blockquote>
<p dir="auto"><code>Condition</code>是 JDK1.5 之后才有的，它具有很好的灵活性，比如可以实现多路通知功能也就是在一个<code>Lock</code>对象中可以创建多个<code>Condition</code>实例（即对象监视器），<strong>线程对象可以注册在指定的<code>Condition</code>中，从而可以有选择性的进行线程通知，在调度线程上更加灵活。 在使用<code>notify()/notifyAll()</code>方法进行通知时，被通知的线程是由 JVM 选择的，用<code>ReentrantLock</code>类结合<code>Condition</code>实例可以实现“选择性通知”</strong> ，这个功能非常重要，而且是 <code>Condition</code> 接口默认提供的。而<code>synchronized</code>关键字就相当于整个 <code>Lock</code> 对象中只有一个<code>Condition</code>实例，所有的线程都注册在它一个身上。如果执行<code>notifyAll()</code>方法的话就会通知所有处于等待状态的线程，这样会造成很大的效率问题。而<code>Condition</code>实例的<code>signalAll()</code>方法，只会唤醒注册在该<code>Condition</code>实例中的所有等待线程。</p>
</blockquote>
<div class="markdown-heading" dir="auto"><h2 tabindex="-1" class="heading-element" dir="auto">参考文献</h2><a id="user-content-参考文献" class="anchor" aria-label="Permalink: 参考文献" href="#参考文献"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul dir="auto">
<li>深入理解 Java 系列 | BlockingQueue 用法详解：<a href="https://juejin.cn/post/6999798721269465102" rel="nofollow">https://juejin.cn/post/6999798721269465102</a></li>
<li>深入浅出阻塞队列 BlockingQueue 及其典型实现 ArrayBlockingQueue：<a href="https://zhuanlan.zhihu.com/p/539619957" rel="nofollow">https://zhuanlan.zhihu.com/p/539619957</a></li>
<li>并发编程大扫盲：ArrayBlockingQueue 底层原理和实战：<a href="https://zhuanlan.zhihu.com/p/339662987" rel="nofollow">https://zhuanlan.zhihu.com/p/339662987</a></li>
</ul>

</article></div><div class="d-none"></div></section></div></div></div> </div> <!-- --> </div></div></div></div></div></div><div class="ScrollMarksContainer-module__scrollMarksContainer__Eu7uU" id="find-result-marks-container"></div><div class="d-none"></div><div class="d-none"></div></div> <!-- --> <!-- --> </div>
</react-app>




  </div>

</turbo-frame>

    </main>
  </div>

  </div>

          <footer class="footer f6 color-fg-muted color-border-subtle tmp-pt-7 tmp-pb-6 p-responsive" role="contentinfo"  >
  <h2 class='sr-only'>Footer</h2>

  


  <div class="d-flex flex-justify-center flex-items-center flex-column-reverse flex-lg-row flex-wrap flex-lg-nowrap">
    <div class="d-flex flex-items-center flex-shrink-0 mx-2">
      <a aria-label="GitHub Homepage" class="footer-octicon mr-2" href="https://github.com">
        <svg aria-hidden="true" data-component="Octicon" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-mark-github">
    <path d="M10.226 17.284c-2.965-.36-5.054-2.493-5.054-5.256 0-1.123.404-2.336 1.078-3.144-.292-.741-.247-2.314.09-2.965.898-.112 2.111.36 2.83 1.01.853-.269 1.752-.404 2.853-.404 1.1 0 1.999.135 2.807.382.696-.629 1.932-1.1 2.83-.988.315.606.36 2.179.067 2.942.72.854 1.101 2 1.101 3.167 0 2.763-2.089 4.852-5.098 5.234.763.494 1.28 1.572 1.28 2.807v2.336c0 .674.561 1.056 1.235.786 4.066-1.55 7.255-5.615 7.255-10.646C23.5 6.188 18.334 1 11.978 1 5.62 1 .5 6.188.5 12.545c0 4.986 3.167 9.12 7.435 10.669.606.225 1.19-.18 1.19-.786V20.63a2.9 2.9 0 0 1-1.078.224c-1.483 0-2.359-.808-2.987-2.313-.247-.607-.517-.966-1.034-1.033-.27-.023-.359-.135-.359-.27 0-.27.45-.471.898-.471.652 0 1.213.404 1.797 1.235.45.651.921.943 1.483.943.561 0 .92-.202 1.437-.719.382-.381.674-.718.944-.943"></path>
</svg>
</a>
      <span>
        &copy; 2026 GitHub,&nbsp;Inc.
      </span>
    </div>

    <nav aria-label="Footer">
      <h3 class="sr-only" id="sr-footer-heading">Footer navigation</h3>

      <ul class="list-style-none d-flex flex-justify-center flex-wrap mb-2 mb-lg-0" aria-labelledby="sr-footer-heading">


          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to Terms&quot;,&quot;label&quot;:&quot;text:terms&quot;}" href="https://docs.github.com/site-policy/github-terms/github-terms-of-service" data-view-component="true" class="Link--secondary Link">Terms</a>
          </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to privacy&quot;,&quot;label&quot;:&quot;text:privacy&quot;}" href="https://docs.github.com/site-policy/privacy-policies/github-privacy-statement" data-view-component="true" class="Link--secondary Link">Privacy</a>
          </li>


            <li class="mx-2">
              <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to security&quot;,&quot;label&quot;:&quot;text:security&quot;}" href="https://github.com/security" data-view-component="true" class="Link--secondary Link">Security</a>
            </li>

            <li class="mx-2">
              <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to status&quot;,&quot;label&quot;:&quot;text:status&quot;}" href="https://www.githubstatus.com/" data-view-component="true" class="Link--secondary Link">Status</a>
            </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to community&quot;,&quot;label&quot;:&quot;text:community&quot;}" href="https://github.community/" data-view-component="true" class="Link--secondary Link">Community</a>
          </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to docs&quot;,&quot;label&quot;:&quot;text:docs&quot;}" href="https://docs.github.com/" data-view-component="true" class="Link--secondary Link">Docs</a>
          </li>

          <li class="mx-2">
            <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to contact&quot;,&quot;label&quot;:&quot;text:contact&quot;}" href="https://support.github.com?tags=dotcom-footer" data-view-component="true" class="Link--secondary Link">Contact</a>
          </li>

          
<li class="mx-2" >
  <cookie-consent-link>
    <button
      type="button"
      class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent"
      data-action="click:cookie-consent-link#showConsentManagement"
      data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;cookies&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;cookies_link_subfooter_footer&quot;}"
    >
      Manage cookies
    </button>
  </cookie-consent-link>
</li>

  <li class="mx-2">
    <cookie-consent-link>
      <button
        type="button"
        class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent text-left"
        data-action="click:cookie-consent-link#showConsentManagement"
        data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;dont_share_info&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;dont_share_info_link_subfooter_footer&quot;}"
      >
        Do not share my personal information
      </button>
    </cookie-consent-link>
  </li>

      </ul>
    </nav>
  </div>
</footer>



    <ghcc-consent id="ghcc" class="position-fixed bottom-0 left-0" style="z-index: 999999"
      data-locale="en"
      data-initial-cookie-consent-allowed=""
      data-cookie-consent-required="true"
    ></ghcc-consent>




  <div id="ajax-error-message" class="ajax-error-message flash flash-error" hidden>
    <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert">
    <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path>
</svg>
    <button type="button" class="flash-close js-ajax-error-dismiss" aria-label="Dismiss error">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
    </button>
    You can’t perform that action at this time.
  </div>

    <template id="site-details-dialog">
  <details class="details-reset details-overlay details-overlay-dark lh-default color-fg-default hx_rsm" open>
    <summary role="button" aria-label="Close dialog"></summary>
    <details-dialog class="Box Box--overlay d-flex flex-column anim-fade-in fast hx_rsm-dialog hx_rsm-modal">
      <button class="Box-btn-octicon m-0 btn-octicon position-absolute right-0 top-0" type="button" aria-label="Close dialog" data-close-dialog>
        <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x">
    <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path>
</svg>
      </button>
      <div class="octocat-spinner tmp-my-6 js-details-dialog-spinner"></div>
    </details-dialog>
  </details>
</template>

    <div class="Popover js-hovercard-content position-absolute" style="display: none; outline: none;">
  <div class="Popover-message Popover-message--bottom-left Popover-message--large Box color-shadow-large" style="width:360px;">
  </div>
</div>

    <template id="snippet-clipboard-copy-button">
  <div class="zeroclipboard-container position-absolute right-0 top-0">
    <clipboard-copy aria-label="Copy code to clipboard" class="ClipboardButton btn js-clipboard-copy m-2 p-0" data-copy-feedback="Copied!" data-tooltip-direction="w">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon m-2 tmp-m-2">
    <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
</svg>
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none m-2 tmp-m-2">
    <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path>
</svg>
    </clipboard-copy>
  </div>
</template>
<template id="snippet-clipboard-copy-button-unpositioned">
  <div class="zeroclipboard-container">
    <clipboard-copy aria-label="Copy code to clipboard" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w">
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon">
    <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path>
</svg>
      <svg aria-hidden="true" data-component="Octicon" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none">
    <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path>
</svg>
    </clipboard-copy>
  </div>
</template>




    </div>
    <div id="js-global-screen-reader-notice" class="sr-only mt-n1" aria-live="polite" aria-atomic="true" ></div>
    <div id="js-global-screen-reader-notice-assertive" class="sr-only mt-n1" aria-live="assertive" aria-atomic="true"></div>
  </body>
</html>

