简体   繁体   中英

Reentrant Lock , busy waiting resolved by the new tryLock method

I was going through java doc description of lockInterruptibly method in ReentrantLock class. My intention was to see if the threads waiting to acquire lock are getting interrupted , may be I am doing it horribly wrong. I know there is an explicit way to call interrupt on Thread and it might be that executorService that I am using has wrapped that concept under it's API.

This behavior is seen with lock method as well

My purpose is to learn this concept in detail

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;

public class LockInterruptibly extends Thread {

    static ExecutorService es = Executors.newFixedThreadPool(5);
    static Lock lock1 = new java.util.concurrent.locks.ReentrantLock();

    public void methodA() {
        if (lock1.tryLock()) {

            try {
                lock1.lockInterruptibly();
                System.out.println("lock acquired by " + this.getName() + "  of method A");
                Thread.sleep(5000);

            } catch (InterruptedException e) {

                System.out.println("this thread " + this.getName() + " was interrupted");
                e.printStackTrace();
            }
        } else {
            System.out.println(this.getName() + "failed to acquire lock");
        }
    }

    public void methodB() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Printed by " + this.getName() + " - " + i);
        }
        lock1.unlock();
        System.out.println(this.getName() + " is exiting at time " + new Date(System.currentTimeMillis()));
    }

    @Override
    public void run() {
        methodA();
        methodB();
    }

    public static void main(String args[]) {
        System.out.println(new Date(System.currentTimeMillis()));
        for (int i = 0; i < 10; i++) {
            Runnable r = new Thread(new LockInterruptibly());
            es.submit(r);
        }
        System.out.println(new Date(System.currentTimeMillis()));
    }
}

Now look at the console output below : console logs showing the relative order, when each thread acquires lock and releases it

My questions is: 1) Why is this interleaving behavior? Why more than 1 thread are able to acquire lock (at least according to console output) , it's almost like a recursive behavior of acquiring locks. or is it just because console output is not in sync with what is happening actually? 2) Has it something to do with executor's way of treating time consuming threads and is normal behavior?

Thanks for your comments ! I was reading about the new Lock api and how you can try to lock before actually 'acquiring' it. So I wanted to code whether the threads are really non blocking or not. The updated code above assigns 5 threads and 10 tasks to executor. All the threads which fail to acquire lock, go on to print the 'for' loop. That means they are "not busy waiting" while the lock-acquiring thread is working in 'critical section'

In contrast I also implemented the synchronized way of doing it

import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Synchronized extends Thread {

    static ExecutorService es = Executors.newFixedThreadPool(5);
    static ArrayList<Object> toBeLocked = new ArrayList<Object>();

    public void methodA() {

        synchronized (toBeLocked) {
            try {
                System.out.println("lock acquired by " + this.getName() + "  of method A");
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                System.out.println("this thread " + this.getName() + "was interrupted");
            }
        }

        for (int i = 0; i < 5; i++) {
            System.out.println("Printed by " + this.getName() + " - " + i);
        }
        System.out.println(this.getName() + " is exiting at time " + new Date(System.currentTimeMillis()));
    }

    @Override
    public void run() {
        methodA();
    }

    public static void main(String args[]) {
        System.out.println(new Date(System.currentTimeMillis()));
        for (int i = 0; i < 10; i++) {
            Runnable r = new Thread(new Synchronized());
            es.submit(r);
        }
        System.out.println(new Date(System.currentTimeMillis()));
    }

}

and found out that indeed all those threads were busy-waiting . Now with the new way of doing it I observed that all the threads which failed to acquire lock went ahead and never cared about returning .Are there any design patterns that answer both, optimum use of thread pools and being able to notify the next most worthy candidate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM