Looking at the following SingletonUtil class we know we can call generateXML method safely.

Code 1: SingletonUtil class for Studio Terminal

static class SingletonUtil {
  var _sbString : StringBuilder
  
  private static var _SELF : SingletonUtil as Instance = new SingletonUtil()

  private construct() {
    _sbString = new StringBuilder()
  }
  
  function generateXML(text : String) : String {
    _sbString.append("")
    _sbString.append(text?:"")
    _sbString.append("")
    var output = _sbString.toString()
    using(_sbString as IMonitorLock) {
      _sbString.delete(0, _sbString.length())
    }
    return output
  }
}

If we generate the XML like the following:

Code 2: GenerateXML via single thread.

print(SingletonUtil.Instance.generateXML("test"))
print(SingletonUtil.Instance.generateXML("test"))
print(SingletonUtil.Instance.generateXML("test"))

The output will be as expected and we can say it is safe:

Output 1

<text>test</text>
<text>test</text>
<text>test</text>

We are complacent that everything is working good since we can run it and can generate the expected Output 1. But don’t forget we are running it in a single thread. Thus we can say that this code is safe for single thread.

Lets try the same but this time with 10 threads and we are expecting the output to be like this:

Output 2

<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>
<text>test</text>

Run the following code in terminal:

Code 3: GenerateXML via multithread.

for (var idx in (1..10)) {
  var thread = new Thread(new Runnable() {
    override function run() {
      print(SingletonUtil.Instance.generateXML("test"))
    }
  })
  thread.start()
}

We will have a hard time generating our expected output this time. And we can say that this not thread-safe. There are three things we can do about this.

1.) If we don't have the source code, we can use locking on the client code. Let's use IMonitorLock for the simplicity and run it in studio terminal. The updated client code can be like the following and can generate Output 2:

Code 4: GenerateXML via multithread with locking.

for (var idx in (1..10)) {
  var thread = new Thread(new Runnable() {
    override function run() {
      var inst = SingletonUtil.Instance
      using(inst as IMonitorLock) {
        print(inst.generateXML("test"))
      }
    }
  })
  thread.start()
}

2.) If we have the source code and can update it, we can make the whole generate XML method to be synchronized like the following and use Code 3 to generate Output 2:

Code 5: SingletonUtil class for Studio Terminal with the whole generateXML is locking.

static class SingletonUtil {
  var _sbString : StringBuilder
  
  private static var _SELF : SingletonUtil as Instance = new SingletonUtil()

  private construct() {
    _sbString = new StringBuilder()
  }
  
  function generateXML(text : String) : String {
    using(_sbString as IMonitorLock) {
      _sbString.append("")
      _sbString.append(text?:"")
      _sbString.append("")
      var output = _sbString.toString()
      _sbString.delete(0, _sbString.length())
      return output
    }
  }
}

3.) If we have the source code and can update it, try to remove the variable state like the following and use Code 3 to generate Output 2:

Code 6: SingletonUtil class for Studio Terminal without shared state.

static class SingletonUtil {
  private static var _SELF : SingletonUtil as Instance = new SingletonUtil()

  private construct() {
  }
  
  function generateXML(text : String) : String {
    var _sbString = new StringBuilder() 
    _sbString.append("")
    _sbString.append(text?:"")
    _sbString.append("")
    var output = _sbString.toString()
    return output
  }
}