如何在Java中的多个线程之间共享资源?

时间:2014-07-08 07:19:08

标签: java multithreading

如何在Java中的多个线程之间共享一个类的数组?

假设我有一个名为Input的类,其数组如下:

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++;
    }

}

现在,我希望2个线程共享Input类的数组,并打印数组的元素(即)两个线程一起应该打印15次(数组中元素的数量)。

这是我的主题类:

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);
        }

    }   

}

最后,设置线程的代码:

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();

    }

}

输出应该是这样的:

线程1

1

线程2

2

线程2

3

线程1

4

线程2

5

依此类推,直到它到达数组中的最后一个元素。

2 个答案:

答案 0 :(得分:2)

您的线程已同步Input.index的访问权限,因此Input类正常。你真正的问题在于MyThread.run。这两行:

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

System.out.println进行2次单独调用。在多线程上下文中,它们必然在线程之间交错,因此输出将超出(全局)顺序。

如果你想保证2个电话是不可分割的,你需要对这2个电话进行排序" atomic" (像同步块一样)。您必须在线程之间共享一个锁,以保护对此代码块的访问,并使它们的执行相互排斥。他们可以共享锁定Object上的内部锁定,或使用java.util.concurrent.locks.ReentrantLock共享显式锁定。

我给出了内部锁的示例代码:

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();
    }
}

请注意:这只会确保" ThreadX n"将一起打印。它不保证输出遵循Input数组中的确切顺序。

BTW,在构造函数中启动Thread是危险的,应该避免。我对您的原始代码进行了细微更改。

答案 1 :(得分:0)

您可以使用低级等待通知方法使用以下方法。

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();
            }
        }
    }
}