Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModelSurrogate.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModelSurrogate.cs	(revision 14318)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModelSurrogate.cs	(revision 14327)
@@ -21,5 +21,7 @@
 #endregion
 
+using System;
 using System.Collections.Generic;
+using System.Diagnostics.Eventing.Reader;
 using System.Linq;
 using HeuristicLab.Common;
@@ -36,5 +38,9 @@
   public sealed class GradientBoostedTreesModelSurrogate : RegressionModel, IGradientBoostedTreesModel {
     // don't store the actual model!
-    private IGradientBoostedTreesModel actualModel; // the actual model is only recalculated when necessary
+    // the actual model is only recalculated when necessary
+    private readonly Lazy<IGradientBoostedTreesModel> actualModel;
+    private IGradientBoostedTreesModel ActualModel {
+      get { return actualModel.Value; }
+    }
 
     [Storable]
@@ -57,13 +63,20 @@
 
     public override IEnumerable<string> VariablesUsedForPrediction {
-      get { return actualModel.Models.SelectMany(x => x.VariablesUsedForPrediction).Distinct().OrderBy(x => x); }
+      get {
+        return ActualModel.Models.SelectMany(x => x.VariablesUsedForPrediction).Distinct().OrderBy(x => x);
+      }
     }
 
     [StorableConstructor]
-    private GradientBoostedTreesModelSurrogate(bool deserializing) : base(deserializing) { }
+    private GradientBoostedTreesModelSurrogate(bool deserializing)
+      : base(deserializing) {
+      actualModel = new Lazy<IGradientBoostedTreesModel>(() => RecalculateModel());
+    }
 
     private GradientBoostedTreesModelSurrogate(GradientBoostedTreesModelSurrogate original, Cloner cloner)
       : base(original, cloner) {
-      if (original.actualModel != null) this.actualModel = cloner.Clone(original.actualModel);
+      IGradientBoostedTreesModel clonedModel = null;
+      if (original.ActualModel != null) clonedModel = cloner.Clone(original.ActualModel);
+      actualModel = new Lazy<IGradientBoostedTreesModel>(CreateLazyInitFunc(clonedModel)); // only capture clonedModel in the closure
 
       this.trainingProblemData = cloner.Clone(original.trainingProblemData);
@@ -75,4 +88,10 @@
       this.m = original.m;
       this.nu = original.nu;
+    }
+
+    private Func<IGradientBoostedTreesModel> CreateLazyInitFunc(IGradientBoostedTreesModel clonedModel) {
+      return () => {
+        return clonedModel == null ? RecalculateModel() : clonedModel;
+      };
     }
 
@@ -96,5 +115,5 @@
       IGradientBoostedTreesModel model)
       : this(trainingProblemData, seed, lossFunction, iterations, maxSize, r, m, nu) {
-      this.actualModel = model;
+      actualModel = new Lazy<IGradientBoostedTreesModel>(() => model);
     }
 
@@ -105,6 +124,5 @@
     // forward message to actual model (recalculate model first if necessary)
     public override IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
-      if (actualModel == null) actualModel = RecalculateModel();
-      return actualModel.GetEstimatedValues(dataset, rows);
+      return ActualModel.GetEstimatedValues(dataset, rows);
     }
 
@@ -119,6 +137,5 @@
     public IEnumerable<IRegressionModel> Models {
       get {
-        if (actualModel == null) actualModel = RecalculateModel();
-        return actualModel.Models;
+        return ActualModel.Models;
       }
     }
@@ -126,6 +143,5 @@
     public IEnumerable<double> Weights {
       get {
-        if (actualModel == null) actualModel = RecalculateModel();
-        return actualModel.Weights;
+        return ActualModel.Weights;
       }
     }
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs	(revision 14318)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs	(revision 14327)
@@ -36,4 +36,5 @@
   public sealed class NearestNeighbourModel : ClassificationModel, INearestNeighbourModel {
 
+    private readonly object kdTreeLockObject = new object();
     private alglib.nearestneighbor.kdtree kdTree;
     public alglib.nearestneighbor.kdtree KDTree {
@@ -47,4 +48,5 @@
       }
     }
+
 
     public override IEnumerable<string> VariablesUsedForPrediction {
@@ -200,11 +202,14 @@
           x[column] = inputData[row, column];
         }
-        int actNeighbours = alglib.nearestneighbor.kdtreequeryknn(kdTree, x, k, false);
-        alglib.nearestneighbor.kdtreequeryresultsdistances(kdTree, ref dists);
-        alglib.nearestneighbor.kdtreequeryresultsxy(kdTree, ref neighbours); // gkronber: this call changes the kdTree data structure
+        int numNeighbours;
+        lock (kdTreeLockObject) { // gkronber: the following calls change the kdTree data structure
+          numNeighbours = alglib.nearestneighbor.kdtreequeryknn(kdTree, x, k, false);
+          alglib.nearestneighbor.kdtreequeryresultsdistances(kdTree, ref dists);
+          alglib.nearestneighbor.kdtreequeryresultsxy(kdTree, ref neighbours);
+        }
 
         double distanceWeightedValue = 0.0;
         double distsSum = 0.0;
-        for (int i = 0; i < actNeighbours; i++) {
+        for (int i = 0; i < numNeighbours; i++) {
           distanceWeightedValue += neighbours[i, columns] / dists[i];
           distsSum += 1.0 / dists[i];
@@ -233,10 +238,13 @@
           x[column] = inputData[row, column];
         }
-        int actNeighbours = alglib.nearestneighbor.kdtreequeryknn(kdTree, x, k, false);
-        alglib.nearestneighbor.kdtreequeryresultsdistances(kdTree, ref dists);
-        alglib.nearestneighbor.kdtreequeryresultsxy(kdTree, ref neighbours);
-
+        int numNeighbours;
+        lock (kdTreeLockObject) {
+          // gkronber: the following calls change the kdTree data structure
+          numNeighbours = alglib.nearestneighbor.kdtreequeryknn(kdTree, x, k, false);
+          alglib.nearestneighbor.kdtreequeryresultsdistances(kdTree, ref dists);
+          alglib.nearestneighbor.kdtreequeryresultsxy(kdTree, ref neighbours);
+        }
         Array.Clear(y, 0, y.Length);
-        for (int i = 0; i < actNeighbours; i++) {
+        for (int i = 0; i < numNeighbours; i++) {
           int classValue = (int)Math.Round(neighbours[i, columns]);
           y[classValue]++;
Index: stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationModel.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationModel.cs	(revision 14318)
+++ stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationModel.cs	(revision 14327)
@@ -22,4 +22,8 @@
 using System.Collections.Generic;
 namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Interface for all classification models.
+  /// <remarks>All methods and properties in in this interface must be implemented thread safely</remarks>
+  /// </summary>
   public interface IClassificationModel : IDataAnalysisModel {
     IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows);
Index: stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisModel.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisModel.cs	(revision 14318)
+++ stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisModel.cs	(revision 14327)
@@ -24,4 +24,8 @@
 
 namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Interface for all data-analysis models (regression/classification/clustering).
+  /// <remarks>All methods and properties in in this interface must be implemented thread safely</remarks>
+  /// </summary>
   public interface IDataAnalysisModel : INamedItem {
     IEnumerable<string> VariablesUsedForPrediction { get; }
Index: stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs	(revision 14318)
+++ stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs	(revision 14327)
@@ -23,4 +23,8 @@
 
 namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Interface for all regression models.
+  /// <remarks>All methods and properties in in this interface must be implemented thread safely</remarks>
+  /// </summary>
   public interface IRegressionModel : IDataAnalysisModel {
     IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows);
Index: stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisModel.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisModel.cs	(revision 14318)
+++ stable/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisModel.cs	(revision 14327)
@@ -22,4 +22,8 @@
 using System.Collections.Generic;
 namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Interface for all time series prognosis models.
+  /// <remarks>All methods and properties in in this interface must be implemented thread safely</remarks>
+  /// </summary> 
   public interface ITimeSeriesPrognosisModel : IRegressionModel {
     IEnumerable<IEnumerable<double>> GetPrognosedValues(IDataset dataset, IEnumerable<int> rows, IEnumerable<int> horizons);
