diff --git a/src/main/java/com/aparapi/internal/kernel/KernelManager.java b/src/main/java/com/aparapi/internal/kernel/KernelManager.java
index 7640a9af9785f383fb0d283f7da6c9c163a236d3..35a20e2c3a67d7e66b6672c2647e413dcec5738b 100644
--- a/src/main/java/com/aparapi/internal/kernel/KernelManager.java
+++ b/src/main/java/com/aparapi/internal/kernel/KernelManager.java
@@ -48,7 +48,7 @@ public class KernelManager {
 
    /**
     * Default KernelManager initialization.<br/>
-    * Convenience method for being overriden to an empty implementation, so that derived 
+    * Convenience method for being overridden to an empty implementation, so that derived 
     * KernelManager classes can provide non static parameters to their constructors.
     */
    protected void setup() {
diff --git a/src/main/java/com/aparapi/internal/kernel/KernelPreferences.java b/src/main/java/com/aparapi/internal/kernel/KernelPreferences.java
index 7c553390fde4758450579a62f4d1f62817b74882..d8cc685d678c013cc71b0f86b4d6c9c85d58dd58 100644
--- a/src/main/java/com/aparapi/internal/kernel/KernelPreferences.java
+++ b/src/main/java/com/aparapi/internal/kernel/KernelPreferences.java
@@ -19,11 +19,15 @@ import com.aparapi.*;
 import com.aparapi.device.*;
 
 import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
 
+/**
+ * Thread safe class holding the kernel preferences for a given kernel class.
+ */
 public class KernelPreferences {
    private final Class<? extends Kernel> kernelClass;
    private final KernelManager manager;
-   private volatile LinkedList<Device> preferredDevices = null;
+   private final AtomicReference<LinkedList<Device>> preferredDevices = new AtomicReference<>(null);
    private final LinkedHashSet<Device> failedDevices = new LinkedHashSet<>();
 
    public KernelPreferences(KernelManager manager, Class<? extends Kernel> kernelClass) {
@@ -39,14 +43,16 @@ public class KernelPreferences {
    public List<Device> getPreferredDevices(Kernel kernel) {
       maybeSetUpDefaultPreferredDevices();
 
+      ArrayList<Device> copy;
+      synchronized (this) {
+         copy = new ArrayList<>(preferredDevices.get());
+      }
+
       if (kernel == null) {
-         return Collections.unmodifiableList(preferredDevices);
+         return Collections.unmodifiableList(copy);
       }
+      
       List<Device> localPreferredDevices = new ArrayList<>();
-      ArrayList<Device> copy;
-      synchronized (preferredDevices) {
-         copy = new ArrayList(preferredDevices);
-      }
       for (Device device : copy) {
          if (kernel.isAllowDevice(device)) {
             localPreferredDevices.add(device);
@@ -56,12 +62,12 @@ public class KernelPreferences {
    }
 
    synchronized void setPreferredDevices(LinkedHashSet<Device> _preferredDevices) {
-      if (preferredDevices != null) {
-         preferredDevices.clear();
-         preferredDevices.addAll(_preferredDevices);
+      if (preferredDevices.get() != null) {
+         preferredDevices.get().clear();
+         preferredDevices.get().addAll(_preferredDevices);
       }
       else {
-         preferredDevices = new LinkedList<>(_preferredDevices);
+         preferredDevices.set(new LinkedList<>(_preferredDevices));
       }
       failedDevices.clear();
    }
@@ -72,19 +78,13 @@ public class KernelPreferences {
    }
 
    synchronized void markPreferredDeviceFailed() {
-      if (preferredDevices.size() > 0) {
-         failedDevices.add(preferredDevices.remove(0));
+      if (preferredDevices.get().size() > 0) {
+         failedDevices.add(preferredDevices.get().remove(0));
       }
    }
 
    private void maybeSetUpDefaultPreferredDevices() {
-      if (preferredDevices == null) {
-         synchronized (this) {
-            if (preferredDevices == null) {
-               preferredDevices = new LinkedList<>(manager.getDefaultPreferences().getPreferredDevices(null));
-            }
-         }
-      }
+	   preferredDevices.compareAndSet(null, new LinkedList<>(manager.getDefaultPreferences().getPreferredDevices(null)));
    }
 
    public List<Device> getFailedDevices() {
diff --git a/src/main/java/com/aparapi/internal/kernel/KernelRunner.java b/src/main/java/com/aparapi/internal/kernel/KernelRunner.java
index fdb45e3eef78ea073d1cc5a64972c41b654ae902..58960925a578a0d2f327b2208178214f90754280 100644
--- a/src/main/java/com/aparapi/internal/kernel/KernelRunner.java
+++ b/src/main/java/com/aparapi/internal/kernel/KernelRunner.java
@@ -1307,6 +1307,8 @@ public class KernelRunner extends KernelRunnerJNI{
             logger.warning("Device failed for " + kernel + ": " + _exception.getMessage());
          }
 
+         //This method is synchronized thus ensuring thread safety on concurrent executions of the same kernel class,
+         //since preferences is shared between such threads.
          preferences.markPreferredDeviceFailed();
 
 //         Device nextDevice = preferences.getPreferredDevice(kernel);
@@ -1337,11 +1339,7 @@ public class KernelRunner extends KernelRunnerJNI{
          boolean legacyExecutionMode = kernel.getExecutionMode() != Kernel.EXECUTION_MODE.AUTO;
 
          ExecutionSettings settings = new ExecutionSettings(preferences, profile, _entrypoint, _range, _passes, legacyExecutionMode);
-         // Two Kernels of the same class share the same KernelPreferences object, and since failure (fallback) generally mutates
-         // the preferences object, we must lock it. Note this prevents two Kernels of the same class executing simultaneously.
-         synchronized (preferences) {
-            return executeInternalOuter(settings);
-         }
+         return executeInternalOuter(settings);
       } finally {
          executing = false;
          clearCancelMultiPass();