如何使用交换机指定交换发生的线程类型?

时间:2013-07-16 16:51:01

标签: java multithreading java.util.concurrent

我有两个Runnable班,ReaderWriter

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.concurrent.Exchanger;

public class Reader implements Runnable {
    private static final int THRESHHOLD = 1000;
    private final int START, STOP;
    private Exchanger<ByteBuffer> exch;
    private RandomAccessFile file;
    private ByteBuffer buffer;

    public Reader(Exchanger<ByteBuffer> ex, RandomAccessFile f, int start, int stop) {
        START = start;
        STOP = stop;
        exch = ex;
        file = f;
        buffer = ByteBuffer.allocate(THRESHHOLD);
        buffer.mark();
    }

    @Override
    public void run() {
        for(int i = START; i < STOP; i++)
            try {
                buffer.put((byte)file.read());
            } catch(IOException e) {
                e.printStackTrace();
            }
        try {
            exch.exchange(buffer);
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
    }
}



import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.concurrent.Exchanger;
import java.util.concurrent.locks.ReentrantLock;

public class Writer implements Runnable {
    private static final int THRESHHOLD = 1000;
    private final int START, STOP;
    private ReentrantLock lock;
    private Exchanger<ByteBuffer> exch;
    private RandomAccessFile file;
    private ByteBuffer buffer;

    public Writer(Exchanger<ByteBuffer> e, ReentrantLock l, RandomAccessFile f, int start, int stop) {
        lock = l;
        START = start;
        STOP = stop;
        exch = e;
        file = f;
    }

    @Override
    public void run() {
        try {
            buffer = exch.exchange(ByteBuffer.allocate(THRESHHOLD));
        } catch(InterruptedException e) {
            e.printStackTrace();
        }
        lock.lock();
        for(int i = START; i < STOP; i++)
            try {
                file.write(buffer.get());
            } catch(IOException e) {
                e.printStackTrace();
            }
        lock.unlock();
    }

}

这两个线程都使用Exchanger来交换相同类型的数据。我怎样才能确保交换仅在ReaderWriter线程之间进行,而不是在两种线程之间进行交换?

2 个答案:

答案 0 :(得分:0)

你的问题有点不清楚。由于您在这些读取器和写入器之间共享相同的交换器实例,因此没有其他线程可以参与此交换。

答案 1 :(得分:0)

如果你害怕“同一类型的两个线程”可以调用同一个Exchanger实例的交换方法(很难从你带来的例子中猜出它是如何可能的,但你知道你的工作组合更好),那么你可以拦截(通过子类或通过委托,无论你更喜欢哪个)这个方法,并检查线程的组合是对还是错,以及在每种情况下应该做什么。 这是一个通过子类化的例子,仅针对最简单的案例进行了测试

public class ThreadStrictExchanger<V> extends Exchanger<V> {
    private Thread waitingThread; 

    @Override
    public V exchange(V x) throws InterruptedException {
        Thread currentThread = Thread.currentThread();
        if (waitingThread == null){
            waitingThread = currentThread;
        } else {
            checkThreads(waitingThread, currentThread);
            waitingThread = null;
        }
        return super.exchange(x);
    }

    private void checkThreads(Thread waitingThread, Thread currentThread) {
        //TODO add here your logic/change  
    }
}

您可以按类型或名称比较两个线程(使用Thread.setName()/ getName())。如果checkThreads方法中两个线程的组合错误,则由您采取什么操作 - 要么抛出异常,要么返回false以指示应该跳过Exchanger.exchange的实际调用(如果它不会破坏调用者的逻辑)。

在Reader和Writer ctors的调用中,将您的类替换为Exchanger。请注意,不会覆盖其他交换方法,但如果需要,逻辑将是相同的。