diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp
index 8dcd7985a40f2..835b6685c7b49 100644
--- a/src/hotspot/share/classfile/classLoader.cpp
+++ b/src/hotspot/share/classfile/classLoader.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -141,8 +141,9 @@ PerfCounter*    ClassLoader::_unsafe_defineClassCallCounter = NULL;
 GrowableArray<ModuleClassPathList*>* ClassLoader::_patch_mod_entries = NULL;
 GrowableArray<ModuleClassPathList*>* ClassLoader::_exploded_entries = NULL;
 ClassPathEntry* ClassLoader::_jrt_entry = NULL;
-ClassPathEntry* ClassLoader::_first_append_entry = NULL;
-ClassPathEntry* ClassLoader::_last_append_entry  = NULL;
+
+ClassPathEntry* volatile ClassLoader::_first_append_entry_list = NULL;
+ClassPathEntry* volatile ClassLoader::_last_append_entry  = NULL;
 #if INCLUDE_CDS
 ClassPathEntry* ClassLoader::_app_classpath_entries = NULL;
 ClassPathEntry* ClassLoader::_last_app_classpath_entry = NULL;
@@ -815,7 +816,7 @@ ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path, bo
 
 // returns true if entry already on class path
 bool ClassLoader::contains_append_entry(const char* name) {
-  ClassPathEntry* e = _first_append_entry;
+  ClassPathEntry* e = first_append_entry();
   while (e != NULL) {
     // assume zip entries have been canonicalized
     if (strcmp(name, e->name()) == 0) {
@@ -826,11 +827,14 @@ bool ClassLoader::contains_append_entry(const char* name) {
   return false;
 }
 
+// The boot append entries are added with a lock, and read lock free.
 void ClassLoader::add_to_boot_append_entries(ClassPathEntry *new_entry) {
   if (new_entry != NULL) {
+    MutexLocker ml(Bootclasspath_lock, Mutex::_no_safepoint_check_flag);
     if (_last_append_entry == NULL) {
-      assert(_first_append_entry == NULL, "boot loader's append class path entry list not empty");
-      _first_append_entry = _last_append_entry = new_entry;
+      _last_append_entry = new_entry;
+      assert(first_append_entry() == NULL, "boot loader's append class path entry list not empty");
+      Atomic::release_store(&_first_append_entry_list, new_entry);
     } else {
       _last_append_entry->set_next(new_entry);
       _last_append_entry = new_entry;
@@ -944,7 +948,7 @@ void ClassLoader::print_bootclasspath() {
   }
 
   // appended entries
-  e = _first_append_entry;
+  e = first_append_entry();
   while (e != NULL) {
     tty->print("%s ;", e->name());
     e = e->next();
@@ -1252,7 +1256,7 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, bool search_append_only, TR
     assert(classpath_index == 0, "The classpath_index has been incremented incorrectly");
     classpath_index = 1;
 
-    e = _first_append_entry;
+    e = first_append_entry();
     while (e != NULL) {
       stream = e->open_stream(file_name, CHECK_NULL);
       if (NULL != stream) {
@@ -1427,7 +1431,7 @@ void ClassLoader::record_result(InstanceKlass* ik, const ClassFileStream* stream
 // Initialize the class loader's access to methods in libzip.  Parse and
 // process the boot classpath into a list ClassPathEntry objects.  Once
 // this list has been created, it must not change order (see class PackageInfo)
-// it can be appended to and is by jvmti and the kernel vm.
+// it can be appended to and is by jvmti.
 
 void ClassLoader::initialize() {
   EXCEPTION_MARK;
diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp
index 9e0dde6464ee7..e00892c423d9e 100644
--- a/src/hotspot/share/classfile/classLoader.hpp
+++ b/src/hotspot/share/classfile/classLoader.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -53,6 +53,7 @@ class ClassPathEntry : public CHeapObj<mtClass> {
   ClassPathEntry* next() const;
   virtual ~ClassPathEntry() {}
   void set_next(ClassPathEntry* next);
+
   virtual bool is_modules_image() const { return false; }
   virtual bool is_jar_file() const { return false; }
   // Is this entry created from the "Class-path" attribute from a JAR Manifest?
@@ -214,9 +215,13 @@ class ClassLoader: AllStatic {
   // 3. the boot loader's append path
   //    [-Xbootclasspath/a]; [jvmti appended entries]
   //    Note: boot loader append path does not support named modules.
-  static ClassPathEntry* _first_append_entry;
+  static ClassPathEntry* volatile _first_append_entry_list;
+  static ClassPathEntry* first_append_entry() {
+    return Atomic::load_acquire(&_first_append_entry_list);
+  }
+
   // Last entry in linked list of appended ClassPathEntry instances
-  static ClassPathEntry* _last_append_entry;
+  static ClassPathEntry* volatile _last_append_entry;
 
   // Info used by CDS
   CDS_ONLY(static ClassPathEntry* _app_classpath_entries;)
@@ -234,7 +239,7 @@ class ClassLoader: AllStatic {
   CDS_ONLY(static ClassPathEntry* app_classpath_entries() {return _app_classpath_entries;})
   CDS_ONLY(static ClassPathEntry* module_path_entries() {return _module_path_entries;})
 
-  static bool has_bootclasspath_append() { return _first_append_entry != NULL; }
+  static bool has_bootclasspath_append() { return first_append_entry() != NULL; }
 
  protected:
   // Initialization:
diff --git a/src/hotspot/share/classfile/classLoader.inline.hpp b/src/hotspot/share/classfile/classLoader.inline.hpp
index 5d10272e522eb..aa362f3112c06 100644
--- a/src/hotspot/share/classfile/classLoader.inline.hpp
+++ b/src/hotspot/share/classfile/classLoader.inline.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,7 +48,7 @@ inline ClassPathEntry* ClassLoader::classpath_entry(int n) {
     // the _jrt_entry is not included in the _first_append_entry
     // linked list, it must be accounted for when comparing the
     // class path vs. the shared archive class path.
-    ClassPathEntry* e = ClassLoader::_first_append_entry;
+    ClassPathEntry* e = first_append_entry();
     while (--n >= 1) {
       assert(e != NULL, "Not that many classpath entries.");
       e = e->next();
@@ -72,7 +72,7 @@ inline int ClassLoader::num_boot_classpath_entries() {
   Arguments::assert_is_dumping_archive();
   assert(has_jrt_entry(), "must have a java runtime image");
   int num_entries = 1; // count the runtime image
-  ClassPathEntry* e = ClassLoader::_first_append_entry;
+  ClassPathEntry* e = first_append_entry();
   while (e != NULL) {
     num_entries ++;
     e = e->next();
@@ -82,7 +82,7 @@ inline int ClassLoader::num_boot_classpath_entries() {
 
 inline ClassPathEntry* ClassLoader::get_next_boot_classpath_entry(ClassPathEntry* e) {
   if (e == ClassLoader::_jrt_entry) {
-    return ClassLoader::_first_append_entry;
+    return first_append_entry();
   } else {
     return e->next();
   }
diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp
index 4559f9d279d1f..d3694e342bb8f 100644
--- a/src/hotspot/share/prims/jvmtiEnv.cpp
+++ b/src/hotspot/share/prims/jvmtiEnv.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -659,13 +659,6 @@ JvmtiEnv::AddToBootstrapClassLoaderSearch(const char* segment) {
       return JVMTI_ERROR_ILLEGAL_ARGUMENT;
     }
 
-    // lock the loader
-    Thread* thread = Thread::current();
-    HandleMark hm(thread);
-    Handle loader_lock = Handle(thread, SystemDictionary::system_loader_lock());
-
-    ObjectLocker ol(loader_lock, thread);
-
     // add the jar file to the bootclasspath
     log_info(class, load)("opened: %s", zip_entry->name());
 #if INCLUDE_CDS
diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp
index fea5e23cf43cd..4d74d70ba509f 100644
--- a/src/hotspot/share/runtime/mutexLocker.cpp
+++ b/src/hotspot/share/runtime/mutexLocker.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -156,6 +156,7 @@ Mutex*   CDSLambda_lock               = NULL;
 Mutex*   DumpRegion_lock              = NULL;
 Mutex*   ClassListFile_lock           = NULL;
 #endif // INCLUDE_CDS
+Mutex*   Bootclasspath_lock           = NULL;
 
 #if INCLUDE_JVMCI
 Monitor* JVMCI_lock                   = NULL;
@@ -352,6 +353,7 @@ void mutex_init() {
   def(DumpRegion_lock              , PaddedMutex  , leaf,        true,  _safepoint_check_never);
   def(ClassListFile_lock           , PaddedMutex  , leaf,        true,  _safepoint_check_never);
 #endif // INCLUDE_CDS
+  def(Bootclasspath_lock           , PaddedMutex  , leaf,        false, _safepoint_check_never);
 
 #if INCLUDE_JVMCI
   def(JVMCI_lock                   , PaddedMonitor, nonleaf+2,   true,  _safepoint_check_always);
diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp
index a4a5865cf3c62..de9fe972c1a6e 100644
--- a/src/hotspot/share/runtime/mutexLocker.hpp
+++ b/src/hotspot/share/runtime/mutexLocker.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -158,6 +158,8 @@ extern Mutex*   CodeHeapStateAnalytics_lock;     // lock print functions against
 extern Monitor* JVMCI_lock;                      // Monitor to control initialization of JVMCI
 #endif
 
+extern Mutex*   Bootclasspath_lock;
+
 extern Mutex* tty_lock;                          // lock to synchronize output.
 
 // A MutexLocker provides mutual exclusion with respect to a given mutex