drunkenfist
drunkenfist

Reputation: 3038

How do I share a resource between multiple threads in Java?

How do I share an array of a class between multiple threads in Java?

Say I have a class called Input with an array as below:

public class Input {
    int index;
    int[] input = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

    public Input(){
        index = 0;
    }

    public void print(int index){
        System.out.println(input[index]);
    }

    synchronized public int getIndex(){
        if(index == 15)
            return -1;
        return index++;
    }

}

Now, I want 2 threads to share the array of Input class, and print the elements of the array (i.e) both the threads together should print 15 times (the number of elements in the array) in total.

This is my thread class:

public class MyThread implements Runnable{

    Thread t;
    int index;
    Input ip;

    public MyThread(Input ip, String name){
        t = new Thread(this, name);
        this.ip = ip;
        index = 0;
        t.start();
    }

    @Override
    public void run() {     
        while((index=ip.getIndex())!=-1){
            System.out.println(t.getName());
            ip.print(index);
        }

    }   

}

And finally, the code which sets up the threads:

public class Caller {

    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        Input ip = new Input();
        MyThread t1 = new MyThread(ip, "Thread1");
        MyThread t2 = new MyThread(ip, "Thread2");
        t1.t.join();
        t2.t.join();

    }

}

The output should be something like:

Thread1

1

Thread2

2

Thread2

3

Thread1

4

Thread2

5

and so on till it reaches the last element in the array.

Upvotes: 5

Views: 13425

Answers (2)

paras4all
paras4all

Reputation: 51

You can use below approach using low-level wait-notify methods.

package com.thread;

/*Print 1 to 15 together by 2 threads*/

public class Print1To15 {

    static int[] input = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };

    public static void main(String[] args) throws InterruptedException {
        MyThread t1 = new MyThread(input);
        MyThread t2 = new MyThread(input);
        Thread thread1 = new Thread(t1, "Thread 1");
        Thread thread2 = new Thread(t2, "Thread 2");

        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
    }
}

class MyThread implements Runnable {
    int[] array;
    static int i = 0;
    final static Object obj = new Object();

    MyThread(int[] array) {
        this.array = array;
    }

    @Override
    public void run() {
        synchronized (obj) {
            while (i <= 14) {
                if (array[i] % 2 != 0 && Thread.currentThread().getName().equals("Thread 1")) {
                    System.out.println(Thread.currentThread().getName() + " printing " + array[i]);
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else if (array[i] % 2 == 0 && Thread.currentThread().getName().equals("Thread 2")) {
                    System.out.println(Thread.currentThread().getName() + " printing " + array[i]);
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                i++;
                obj.notifyAll();
            }
        }
    }
}

Upvotes: 0

James
James

Reputation: 597

Your threads have synchronized access to Input.index, so the Input class is fine. Your real problem lies in MyThread.run. These two lines:

    System.out.println(t.getName());
    ip.print(index);

make 2 separate calls to System.out.println. In a multithreaded context, they are bound to be interleaved between threads, hence the output will be out of (global) order.

If you want to guarantee that the 2 calls are inseparable, you need to make this 2 calls sort of "atomic" (like a synchronization block). You'll have to share a lock between your threads to protect access to this code block and make their execution mutual exclusive. They can share either an intrinsic lock on a lock Object, or an explicit lock by using java.util.concurrent.locks.ReentrantLock.

I'm giving a sample code for an intrinsic lock:

public class MyThread implements Runnable{

    Input ip;
    Object lock;

    public MyThread(Input ip, Object lock){
        this.ip = ip;
        this.lock = lock;
    }

    @Override
    public void run() {
        int index = -1;     
        while((index=ip.getIndex())!=-1){
            synchronized(lock) {
                System.out.println(Thread.currentThread().getName());
                ip.print(index);
            }
        }
    }   
}


public class Caller {

    public static void main(String[] args) throws InterruptedException {
        Input ip = new Input();
        Object lock = new Object();
        Thread t1 = new Thread(new MyThread(ip, lock), "Thread1");
        Thread t2 = new Thread(new MyThread(ip, lock), "Thread2");
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

Please note: this will only ensure that "ThreadX n" will print together. It does not guarantee that the output follows the exact order in the Input array.

BTW, starting a Thread in the constructor is dangerous and should be avoided. I made minor changes to your original code.

Upvotes: 1

Related Questions