Mutex programming in Java

I am new to Computer Science and I am reading a book that introduces topics and mutexes. I've tried programming a mutex in Java, which seems to work most of the time, but each won't do that often.

In my code, the critical section adds numbers from 1 to 10 to the static variable j, resulting in 55 (if j starts at 0). If I run three threads at the same time through the critical section, I get random final j values, which makes sense.

But with the muteca below, most of the time I get the last j 165 (55 * 3) which I want, but sometimes I get random j values. Can anyone take a look at my code and see what's going on? Thank!

public class Mythread extends Thread {

    private static int j = 0;
    private static int mutex = 0;  // Initial value of the mutex is 0;

    @Override
    public void run() {


        while (test_and_set(mutex) == 1) {

            // wait here if mutex is 1
            System.out.println("Thread waiting..");
        } 

        for (int i = 1; i <= 10; i++) { // Start of Critical section 
            j += i;                     // 

        }
        System.out.println(j);       // End of Critical section 
                                     // Should add on 55 to j if one thread is running through the CS

       mutex = 0; // Thread that has finished the CS sets the mutex to 0.

    }

    public static int test_and_set(int oldMutexValue) {
        if (mutex == 0) {
            mutex = 1;
        }
        return oldMutexValue;
    }


}

public class Test1 {




    public static void main(String[] args) {

        Mythread thread1 = new Mythread();
        Mythread thread2 = new Mythread();
        Mythread thread3 = new Mythread();
        thread1.start();
        thread2.start();
        thread3.start();

    }



}

      

+3


source to share


3 answers


You are creating a race condition and using forward blocking . Spinning locks are deprecated in Java. Consider the following:

One thread starts executing while the other two are waiting. The other two streams are waiting. The other two threads now deadlock at the same time, and both start execution, giving you the odd J value, because both are simultaneously modifying it.

To fix it:

Implement Java methodology with synchronized . Synchronized is a Java internal method for thread safety and flow control. No revolving locks!

Change your MyThread to the following:



public class MyThread extends Thread {
private static int j = 0;

public void run() {
    synchronized(this) {
        for (int i = 1; i <= 10; i++) {
            j += i;
        }
    }
    System.out.println(j);
}

      

Synchronized can surround any critical piece of code that could lead to race conditions, concurrent data changes, etc. Note that there is no specific lock. Note that sync takes its own object as a parameter, as you sync control over that object, but you can just as easily take other objects as a parameter if needed, which gives you a lot of flexibility when blocking things.

The rest of your code will work the same!

Hope this helps!

0


source


(1) The test_and_set () function looks like it should emulate a hardware instruction of the same name that has been used in many computer architectures. But what should test_and_set () return? Hint. It must tell the caller if the caller has "won" the mutex.

(2) You have more problem with your test_and_set (): It's not atomic. If you were wondering why a computer that has "test" instructions and "installed" instructions should also have a test_and_set (aka, TAS) instruction, because the TAS command is atomic. I assume you need to know more about what this means (see 4 below).

(3) TAS is archaic. Modern computers implement something called Compare and Swap, Compare and Set (CAS), which is more powerful. If you want to know how modern timing algorithms work, you should use CAS instead of TAS.



The Java Standard Library has a real, truly atomic CAS function that you can call: it java.util.concurrent.atomic.AtomicInteger.CompareAndSet (...). http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicInteger.html

(4) You should probably not try to learn how to write synchronization functions / objects until you have more experience with these functions. What brings you out is that you haven't synchronized the test_and_set () function. If you did not know this, then you have little experience with writing multi-threaded code.

Learn how to use sync objects first. http://docs.oracle.com/javase/tutorial/essential/concurrency/ Then you might worry about how they are implemented.

+1


source


There is a java.util.concurrency.Semaphore class for your task:

package test;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class MyThread extends Thread {
    private static int j = 0;
    private static final Semaphore mutex = new Semaphore(1, true);

    @Override
    public void run() {
        try {
            while (!mutex.tryAcquire(100, TimeUnit.MILLISECONDS)) {
                System.out.println("Thread waiting.");
            }
        }
        catch (InterruptedException e) {
            System.out.println("Thread interrupted.");
            return;
        }

        try {
            for (int i = 1; i <= 10; i++) { // Start of Critical section
                j += i;                     //

            }
            System.out.println(j);       // End of Critical section
            // Should add on 55 to j if one thread is running through the CS
        }
        finally {
            mutex.release(); // Thread that has finished the CS sets the mutex to 0.
        }
    }
}

      

0


source







All Articles