Hello Members,

I am trying to solve the following problem using threads:

Thread_1 outputs values from 1 to 1000. Thread_1 waits. Thread_2 outputs values from 1 to 1000. Thread_2 now waits. Thread_1 outputs values from 1000 to 2000. Thread_1 is done. Thread_2 outputs values from 1000 to 2000. Thread_1 exits followed by Thread_2.

I have the following program where I use a Lock to ensure only one thread is in the critical section. What I am having trouble with is switching between threads as mentioned in the previous paragraph. Any help would be much appreciated.

Thank you!


The Lock Class:

public class Lock{
  
  private boolean isLocked = false;
 
  
  public synchronized void lock() throws InterruptedException{
    while(isLocked){
      wait();
    }
    isLocked = true;
    }
  
  public synchronized void unlock(){
    isLocked = false;
    notify();
  }
}

The Thread Class and the main program:

class Share extends Thread
{
 
 private static Lock lock = new Lock();
  
 Share(String threadname)
 {
   super(threadname);
 }
 
 public synchronized void print(int start, int end)
 {
       for(int i = start; i<=end;i++)
            {
                System.out.println(Thread.currentThread().getName() + "  " + i);
            }
 }        
 
 public synchronized void run() 
 {
          
            try{
                    lock.lock();
                }
       catch (InterruptedException e){}
          
    try{
       lock.lock();
       }
       catch (InterruptedException e){}
       
      
        
      
      

        lock.unlock();
             
    
}
}
public class SynThread1
{
  public static void main(String[] args)
  {
    Share t1=new Share("One");
    t1.start();
    Share t2=new Share("Two");
    t2.start();
   }
}

Edit: Never mind, answered my own question.

Hello,

What was the question? Do you have any suggestions for my questions?

Thank you!

Is it necessary for you to write your own lock implementation for this or are you free to use any standard classes for the same?

Hello sos,

Either way is fine. Any pointers from your end about standard classes would be appreciated.

Thank you!

OK, here we go.

Thread_1 outputs values from 1 to 1000. Thread_1 waits. Thread_2 outputs values from 1 to 1000. Thread_2 now waits. Thread_1 outputs values from 1000 to 2000. Thread_1 is done. Thread_2 outputs values from 1000 to 2000. Thread_1 exits followed by Thread_2.

I'm not really convinced with the scenario you have presented since it can easily be solved by a single thread, esp given your requirement that while thread1 is counting, thread 2 shouldn't do anything. The answer I'm presenting here is assuming that you have a valid scenario which justifies this approach i.e. thread 1 does task A which thread 2 depends on (task B), thread 2 does task B which thread 1 depends on (task C), thread 1 does task C on which thread 2 depends (task D). Maybe if you posted the real requirement I might try to help you with an even better solution.

One way of doing this would be to use a SynchronousQueue as a sequencer here. The unique thing about this queue is that its "put" and "take" operations for an item block as long as there is nothing on the other side (i.e. another task aka thread) to "take" or "put" the item respectively.

The way we use this class is pass it to the two work unit classes which we have (worker 1 and 2) and ensure that the sequencing is orchestrated between them using this queue. Here when I say worker 1, I mean thread 1 and the same with worker 2. The way this works is:

  • Worker 1 created as a thread subclass; the logic of this class is to assume the role of your thread 1. It counts till 1000 and waits for the other party to do the same. Till it counts, the other party (worker 2) does nothing.
  • Worker 2 again is created as a thread subclass; the logic of this class is to assume the role of your thread 2. It waits for worker 1 to count to 1000, then starts counting to 1000 and again waits for the worker 1 to complete counting till 2000.

The code contains the sequence of steps performed:

public class Tester {

    public static void main(final String[] args) throws Exception {
        SynchronousQueue<Object> q = new SynchronousQueue<Object>();
        List<Thread> threads = new ArrayList<Thread>();
        threads.add(new Worker2(q));
        threads.add(new Worker1(q));
        for(Thread t : threads) {
            t.start();
        }
        for(Thread t : threads) {
            t.join();
        }
    }
    
}

class Worker1 extends Thread {
    
    static int COUNT = 1000;
    
    private final SynchronousQueue<Object> q;
    
    public Worker1(final SynchronousQueue<Object> q) {
        super("worker1");
        this.q = q;
    }
    
    @Override
    public void run() {
        try {
            // count from 1 to COUNT
            for(int i = 1; i <= COUNT; ++i) {
                System.out.printf("%s from %s%n", Integer.toString(i), Thread.currentThread().getName());
            }
            
            // put in the queue; block till worker 2 picks this up
            q.put(new Object());
            
            // now wait for worker 2 to complete its work (1 to COUNT) and put a result in queue
            q.take();
            
            // finish off the task
            for(int i = COUNT + 1; i <= COUNT * 2; ++i) {
                System.out.printf("%s from %s%n", Integer.toString(i), Thread.currentThread().getName());
            }
            
            // signal the worker 2 which is waiting for this worker to complete by calling "take()"
            q.put(new Object());
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    
}

class Worker2 extends Thread {
    
    static int COUNT = 1000;
    
    private final SynchronousQueue<Object> q;
    
    public Worker2(final SynchronousQueue<Object> q) {
        super("worker2");
        this.q = q;
    }
    
    @Override
    public void run() {
        try {
            // wait for the worker 1 to finish counting from 1 to COUNT
            q.take();
            
            // do the job of counting from 1 to COUNT while worker 1 is waiting
            for(int i = 1; i <= COUNT; ++i) {
                System.out.printf("%s from %s%n", Integer.toString(i), Thread.currentThread().getName());
            }
            
            // signal the worker 1 to resume its counting
            q.put(new Object());
            
            // wait for worker 1 to finish the counting task
            q.take();
            
            // resume our own counting and finish things off
            for(int i = COUNT + 1; i <= COUNT * 2; ++i) {
                System.out.printf("%s from %s%n", Integer.toString(i), Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    
}

Oh, and btw, the lock implementation you had in your previous post was pretty much broken. Look at the source code of ReentrantLock class for how locks should actually be implemented (it's difficult to get it right) or for a crude implementation, look at Neil's lock class.

Hello sos,

Thanks a lot for the clear and detailed response!! Also, thank you for the pointing out the error in my Lock Class. Your post was extremely helpful!

Regards

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.