-2

I was reading about synchronized methods/statements in the Java tutorial here: https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

It made sense, but once I started coding I came across a dilemma: What do I do about the object's access to its own fields?

Consider this example:

public class MyClass extends Thread {

    private PrintWriter printWriter;

    public synchronized void setPrintWriter(PrintWriter pw){
        printWriter = pw;
    }

    public synchronized PrintWriter getPrintWriter(){
        return printWriter;
    }

    @Override
    public void run() {
        PrintWriter pw = getPrintWriter();
        while (!this.isInterrupted()) {

            try {
                pw.println("some stuff");
                pw.flush();
                Thread.sleep(1000);
            }
            catch (InterruptedException e){
                //pass the interrupt along (will terminate the loop)
                Thread.currentThread().interrupt();
            }
        }
        //finish by printing this when we've received an interrupt
        pw.println("some more stuff");
    }
}

This will work, but it seems a little ridiculous to use a getter to get a copy pw, when I can just use printWriter directly. But I'm not sure if it's necessary in this case, or in some other case similar to this. Maybe it protects me from corruption if some other thread called setPrintWriter at the same time that I was using printWriter?

Stephen
  • 8,508
  • 12
  • 56
  • 96
  • The fact that the class is accessing its own field does nothing to "protect you from corruption". You might not need the sync in this case (I'm not sure what you're actually doing with `setPrintWriter`), but it wouldn't be for that reason. – khelwood Mar 28 '18 at 21:08
  • Just a note, unrelated to your question, typically you want to implement ```Runnable``` or rather than extending ```Thread``` to do a piece of work. See [this post for more info](https://stackoverflow.com/questions/541487/implements-runnable-vs-extends-thread) – jseashell Mar 28 '18 at 21:12

1 Answers1

1

The question is not that "the object accesses its own fields". Any other class that calls your methods also (indirectly) access the fields.

The question is, "if many threads access a given instance of that class, it is safe ?"

In your class, if threads A and B use a given instance of your class, they will both be able to access the printWriter field. If this is done without proper synchronization, bad things could happen (value caching, data corruption, etc.)

The easiest way to ensure proper thread-safety is to follow this recipe :

  • List all the fields that can be accessed from the outside, for example by calling a method
  • For each field or group of related fields (as in "fields that must be modified simultaneously", eg. age and birthDate), define a protection strategy : monitors (via the synchronized keyword), Locks (in java.util.concurrent.locks), atomic classes (AtomicInteger...), etc. You have plenty of choice here.
  • For each path that leads to the variable(s) listed at step 1, ensure that the synchronization policy is applied. And by "each path", I mean you must apply synchronization even on paths that only access those variables in read-only mode. This is important to avoid reading stale values (think: "update/pull" in svn/git).

In that regard, you implemented synchronization correctly here : all paths leading to printWriter are covered by synchronized (in write- and read modes), so you're good.

Olivier Croisier
  • 6,139
  • 25
  • 34
  • Could you still face problems due to having multiple references to the same object? In my example getPrintWriter is synchronized. But what if two different threads used it at some point? Now they have two different local objects which probably refer to the same space in memory. Operations on those local objects might not pass through synchronized methods, depending on how the PrintWriter class is set up. – Stephen Mar 29 '18 at 14:40