Index: src/org/openstreetmap/josm/actions/UploadAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/UploadAction.java	(revision 13076)
+++ src/org/openstreetmap/josm/actions/UploadAction.java	(working copy)
@@ -9,6 +9,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 
 import javax.swing.JOptionPane;
 
@@ -24,8 +25,8 @@
 import org.openstreetmap.josm.data.osm.Changeset;
 import org.openstreetmap.josm.gui.HelpAwareOptionPane;
 import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.io.AsynchronousUploadPrimitivesTask;
 import org.openstreetmap.josm.gui.io.UploadDialog;
-import org.openstreetmap.josm.gui.io.UploadPrimitivesTask;
 import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.util.GuiHelper;
@@ -257,14 +258,14 @@
             hook.modifyChangesetTags(changesetTags);
         }
 
-        MainApplication.worker.execute(
-                new UploadPrimitivesTask(
-                        UploadDialog.getUploadDialog().getUploadStrategySpecification(),
-                        layer,
-                        apiData,
-                        cs
-                )
-        );
+        Optional<AsynchronousUploadPrimitivesTask> optionTask = AsynchronousUploadPrimitivesTask.createAsynchronousUploadTask(
+                UploadDialog.getUploadDialog().getUploadStrategySpecification(),
+                layer,
+                apiData,
+                cs);
+        if (optionTask.isPresent()) {
+            MainApplication.worker.execute(optionTask.get());
+        }
     }
 
     @Override
Index: src/org/openstreetmap/josm/gui/io/AsynchronousUploadPrimitivesTask.java
===================================================================
--- src/org/openstreetmap/josm/gui/io/AsynchronousUploadPrimitivesTask.java	(nonexistent)
+++ src/org/openstreetmap/josm/gui/io/AsynchronousUploadPrimitivesTask.java	(working copy)
@@ -0,0 +1,125 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.io;
+
+import org.openstreetmap.josm.data.APIDataSet;
+import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.progress.ProgressTaskId;
+import org.openstreetmap.josm.gui.util.GuiHelper;
+import org.openstreetmap.josm.io.UploadStrategySpecification;
+import org.openstreetmap.josm.tools.I18n;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Allows to upload the primitives in background
+ */
+public class AsynchronousUploadPrimitivesTask extends UploadPrimitivesTask {
+
+    // Static instance
+    private static AsynchronousUploadPrimitivesTask asynchronousUploadPrimitivesTask = null;
+
+    // flag to hide primitives to be uploaded.
+    private static final boolean hideUploadingPrimitives = false;
+
+    private final ProgressTaskId taskId;
+    private final DataSet dataSet;
+    private final List<OsmPrimitive> osmPrimitiveList;
+
+    // Restrict creating more Asynchronous upload tasks
+    private AsynchronousUploadPrimitivesTask(UploadStrategySpecification uploadStrategySpecification, OsmDataLayer osmDataLayer, APIDataSet apiDataSet, Changeset changeset) {
+        super(uploadStrategySpecification,
+                osmDataLayer,
+                apiDataSet,
+                changeset);
+        dataSet = osmDataLayer.data;
+        osmPrimitiveList = apiDataSet.getPrimitives();
+        disablePrimitives(osmPrimitiveList);
+        taskId = new ProgressTaskId("core", "async-upload");
+    }
+
+    private static void disablePrimitives(List <OsmPrimitive> osmPrimitiveList) {
+        for (OsmPrimitive p : osmPrimitiveList) {
+
+            // Disable primitives to be uploaded.
+            p.setDisabledState(hideUploadingPrimitives);
+
+            // Disable the referrers of the primitives to be uploaded.
+            for (OsmPrimitive referrer : p.getReferrers()) {
+                referrer.setDisabledState(hideUploadingPrimitives);
+            }
+        }
+    }
+
+    private static void enablePrimitives(List <OsmPrimitive> osmPrimitiveList) {
+        for (OsmPrimitive p : osmPrimitiveList) {
+
+            // Disable primitives to be uploaded.
+            p.unsetDisabledState();
+
+            // Disable the referrers of the primitives to be uploaded.
+            for (OsmPrimitive referrer : p.getReferrers()) {
+                referrer.unsetDisabledState();
+            }
+        }
+    }
+
+    public static Optional<AsynchronousUploadPrimitivesTask> createAsynchronousUploadTask
+            (UploadStrategySpecification uploadStrategySpecification,
+             OsmDataLayer dataLayer, APIDataSet toUpload, Changeset changeset) {
+        synchronized (AsynchronousUploadPrimitivesTask.class) {
+            if (asynchronousUploadPrimitivesTask != null) {
+                if (!GraphicsEnvironment.isHeadless()) {
+                    GuiHelper.runInEDTAndWait(() ->
+                            JOptionPane.showMessageDialog(MainApplication.parent,
+                                    I18n.tr("A background upload is already in progress. Kindly wait for it to finish before uploading new changes")));
+                }
+                return Optional.empty();
+            } else {
+                DataSet safeCopy = new DataSet(dataLayer.data);
+                asynchronousUploadPrimitivesTask = new AsynchronousUploadPrimitivesTask(
+                        uploadStrategySpecification,
+                        dataLayer,
+                        toUpload,
+                        changeset);
+                return Optional.ofNullable(asynchronousUploadPrimitivesTask);
+            }
+        }
+    }
+
+    public static Optional<AsynchronousUploadPrimitivesTask> getCurrentAsynchronousUploadTask () {
+        return Optional.ofNullable(asynchronousUploadPrimitivesTask);
+    }
+
+    @Override
+    public ProgressTaskId canRunInBackground() {
+        return taskId;
+    }
+
+    @Override
+    protected void realRun() {
+        super.realRun();
+    }
+
+    @Override
+    protected void cancel() {
+        super.cancel();
+        // Free up the async uploader
+        enablePrimitives(osmPrimitiveList);
+        asynchronousUploadPrimitivesTask = null;
+    }
+
+    @Override
+    protected void finish() {
+        super.finish();
+        // Free up the async uploader
+        enablePrimitives(osmPrimitiveList);
+        asynchronousUploadPrimitivesTask = null;
+    }
+}
Index: test/unit/org/openstreetmap/josm/gui/io/AsynchronousUploadPrimitivesTaskTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/gui/io/AsynchronousUploadPrimitivesTaskTest.java	(nonexistent)
+++ test/unit/org/openstreetmap/josm/gui/io/AsynchronousUploadPrimitivesTaskTest.java	(working copy)
@@ -0,0 +1,76 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.io;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import org.junit.*;
+import org.openstreetmap.josm.data.APIDataSet;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.*;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.io.UploadStrategySpecification;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import java.util.*;
+
+public class AsynchronousUploadPrimitivesTaskTest {
+
+    private UploadStrategySpecification strategy;
+    private OsmDataLayer layer;
+    private APIDataSet toUpload;
+    private Changeset changeset;
+    private AsynchronousUploadPrimitivesTask uploadPrimitivesTask;
+
+    /**
+     * Setup tests
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules();
+
+    @Before
+    public void bootStrap() {
+        DataSet dataSet = new DataSet();
+        Node node1 = new Node();
+        Node node2 = new Node();
+        node1.setCoor(new LatLon(0, 0));
+        node2.setCoor(new LatLon(30, 30));
+        Way way = new Way();
+        way.addNode(node1);
+        way.addNode(node2);
+        dataSet.addPrimitive(node1);
+        dataSet.addPrimitive(node2);
+        dataSet.addPrimitive(way);
+
+        toUpload = new APIDataSet(dataSet);
+        layer = new OsmDataLayer(dataSet, "uploadTest", null);
+        strategy = new UploadStrategySpecification();
+        changeset = new Changeset();
+        if (AsynchronousUploadPrimitivesTask.getCurrentAsynchronousUploadTask().isPresent()) {
+            uploadPrimitivesTask = AsynchronousUploadPrimitivesTask.getCurrentAsynchronousUploadTask().get();
+        } else {
+            uploadPrimitivesTask = AsynchronousUploadPrimitivesTask.createAsynchronousUploadTask(strategy, layer, toUpload, changeset).get();
+        }
+    }
+
+    @After
+    public void tearDown () {
+        toUpload = null;
+        layer = null;
+        strategy = null;
+        changeset = null;
+        uploadPrimitivesTask = null;
+    }
+
+    @Test
+    public void testSingleUploadInstance () {
+        Optional<AsynchronousUploadPrimitivesTask> task = AsynchronousUploadPrimitivesTask.createAsynchronousUploadTask(strategy, layer, toUpload, changeset);
+        Assert.assertFalse(task.isPresent());
+    }
+
+    @Test
+    public void testPrimitivesToUploadAreDisabled () {
+        for (OsmPrimitive p : layer.data.allPrimitives()) {
+            Assert.assertTrue(p.isDisabled());
+        }
+    }
+}
