1

我必须创建一个对冲模拟器。有例如。它有10个段,每个段都应该有自己的专用线程模拟段的增长(每次我们要计算段是否长大时,我们都应该进行随机测试)。此外,还应该有一个额外的园丁线程。当它的大小达到 10 时,Garder 应该削减部分(然后他将其大小削减回初始级别 1 并在他的笔记中添加通知)。

我试图让它工作是这样的:

public class Segment implements Runnable {
    private int currentSize;

    @Override
    public void run() {
        if(Math.random() < 0.3)
            incrementSize();
    }

    private synchronized void incrementSize() {
        currentSize++;
    }

    public synchronized int getCurrentSize() {
        return currentSize;
    }

    public synchronized void setCurrentSize(int newSize) {
        currentSize = newSize;
    }
}

public class Gardener implements Runnable {
    private int[] segmentsCutAmount = new int[10]; //Gardener notes
    private Collection<Segment> segments;

    public Gardener(Collection<Segment> segmentsToLookAfter) {
        segments = segmentsToLookAfter;
    }

    @Override
    public void run() {
        while(true) {
            //Have no idea how to deal with 10 different segments here
        }
    }
}

public class Main {
    private Collection<Segment> segments = new ArrayList<>():
    public void main(String[] args) {
        Main program = new Main();
        for(int i = 0; i < 10; i++)
            program.addSegment();

        Thread gardenerThread = new Thread(new Gardener(program.segments));
    }

    private void addSegment(Collection<Segment> segments) {
        Segment segment = new Segment();
        Thread segmentThread = new Thread(segment);
        segmentThread.start();
        segments.add(segment);
    }
}

当段达到最大高度时,我不确定我应该做什么。如果有 10 个园丁,每个人都可以观察一个片段,但不幸的是,园丁是一个孤独的射手——他没有家人,他的朋友很忙,不愿意帮助他。你愿意帮助我吗?:D 我一般都知道同步的基础知识 - 同步方法/块、锁、等待和通知方法,但这次我完全不知道该怎么做 :( 这就像可怕的死锁!当然我不希望被灌输。任何一种提示也会很有帮助。提前谢谢你,祝你有美好的一天!

4

2 回答 2

1

关于那个队列。你可以使用ExecutorService它。

让对冲成长

所以让我们有一个可以生长和切割的树篱。

class Hedge {
    private AtomicInteger height = new AtomicInteger(1);
    public int grow() {
        return height.incrementAndGet();
    }
    public int cut() {
        return height.decrementAndGet();
    }
}

然后你就有了一个可以让对冲成长的环境。这将模拟对冲部分;每个环境只负责其中一个部分。它还会Consumer<Integer>在对冲大小消失时通知 a。

class SectionGrower implements Runnable {
    public static final Random RANDOM = new Random();
    private final Hedge hedge;
    private final Consumer<Integer> hedgeSizeListener;
    public SectionGrower (Hedge h, Consumer<Integer> hl) { 
        hedge = h; 
        hedgeSizeListener = hl 
    }
    public void run() {
        while (true) { // grow forever
            try { 
                // growing the hedge takes up to 20 seconds
                Thread.sleep(RANDOM.nextInt(20)*1000);
                int sectionHeight = hedge.grow();
                hedgeSizeListener.accept(sectionHeight);
            } catch (Exception e) {} // do something here
        }
    }
}

所以在这一点上,你可以做到这一点。

ExecutorService growingExecutor = Executors.newFixedThreadPool(10);
Consumer<Integer> printer = i -> System.out.printf("hedge section has grown to %d\n", i.intValue());
for (int i = 0; i < 10; i++) {
    Hedge section = new Hedge();
    Environment grower = new SectionGrower(section, printer);
    growingExecutor.submit(grower::run);
}

这将增长 10 个树篱部分,并随着它们的增长打印每个树篱部分的当前高度。

添加园丁

所以现在你需要一个可以修剪树篱的园丁。

class Gardener {
    public static final Random RANDOM = new Random();
    public void cutHedge(Hedge h) {
        try { 
            // cutting the hedge takes up to 10 seconds
            Thread.sleep(RANDOM.nextInt(10)*1000);
            h.cut();
        } catch (Exception e) {} // do something here
    }
}

现在你需要一些构造来给他工作;这就是BlockingQueue进来的地方。我们已经确保可以在一个部分增长后Environment通知a ,所以这就是我们可以使用的。Consumer<Integer>

ExecutorService growingExecutor = Executors.newFixedThreadPool(10);
// so this is the queue
ExecutorService gardenerExecutor = Executors.newSingleThreadPool();
Gardener gardener = new Gardener();
for (int i = 0; i < 10; i++) {
    Hedge section = new Hedge();
    Consumer<Integer> cutSectionIfNeeded = i -> {
        if (i > 8) { // size exceeded?
            // have the gardener cut the section, ie adding item to queue
            gardenerExecutor.submit(() -> gardener.cutHedge(section));
        }
    };
    SectionGrower grower = new SectionGrower(section, cutSectionIfNeeded);
    growingExecutor.submit(grower::run);
}

所以我实际上并没有尝试过,但它应该可以进行一些小的调整。

请注意,我AtomicInteger在对冲中使用了,因为它可能会“同时”增长并被切割,因为这发生在不同的线程中。

于 2018-05-06T09:09:26.400 回答
0

下面的代码Gardner等待Segment到达任意值 9。
Segment到达 9 时,它通知Gardner,并等待Gardner完成修剪:

import java.util.ArrayList;
import java.util.Collection;

public class Gardening {

    public static void main(String[] args) {

        Collection<Segment> segments = new ArrayList<>();
        for(int i = 0; i < 2; i++) {
            addSegment(segments);
        }
        Thread gardenerThread = new Thread(new Gardener(segments));
        gardenerThread.start();
    }

    private static void addSegment(Collection<Segment> segments) {
        Segment segment = new Segment();
        Thread segmentThread = new Thread(segment);
        segmentThread.start();
        segments.add(segment);
    }
}

class Gardener implements Runnable {

    private Collection<Segment> segments;
    private boolean isStop = false; //add stop flag

    public Gardener(Collection<Segment> segmentsToLookAfter) {
        segments = segmentsToLookAfter;
    }

    @Override
    public void run() {
        for (Segment segment : segments) {
            follow(segment);
        }
    }

    private void follow(Segment segment) {

        new Thread(() -> {

            Thread t = new Thread(segment);
            t.start();
            synchronized (segment) {

                while(! isStop) {
                    try {
                        segment.wait(); //wait for segment
                    } catch (InterruptedException ex) { ex.printStackTrace();}

                    System.out.println("Trimming Segment " + segment.getId()+" size: "
                            + segment.getCurrentSize() ); //add size to notes
                    segment.setCurrentSize(0); //trim size
                    segment.notify(); //notify so segment continues
                }
            }

        }).start();
    }
}

class Segment implements Runnable {

    private int currentSize;
    private boolean isStop = false; //add stop flag
    private static int segmentIdCounter = 0;
    private int segmentId = segmentIdCounter++; //add an id to identify thread

    @Override
    public void run() {
        synchronized (this) {
            while ( ! isStop ) {

                if(Math.random() < 0.0000001) {
                    incrementSize();
                }

                if(getCurrentSize() >= 9) {
                    notify(); //notify so trimming starts
                    try {
                        wait(); //wait for gardener to finish
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }
    }

    private synchronized void incrementSize() {
        currentSize++;
        System.out.println("Segment " + getId()+" size: "
                + getCurrentSize() );
    }

    public synchronized int getCurrentSize() {  return currentSize;  }

    public synchronized void setCurrentSize(int newSize) {
        currentSize = newSize;
    }
    public int getId() { return segmentId; }
}

相互等待机制也可以用CountDownLatch.
请注意,我对线程的经验是有限的。我希望其他用户发表评论并提出改进建议。

于 2018-05-06T12:05:48.360 回答