我必须创建一个树篱模拟器。有例如。它的10个部分,每个部分应该有自己的专用线程模拟片段的增长(每次我们要计算片段是否长大,我们应该进行随机测试)。 此外还应该有一个额外的园丁螺纹。 因此,当它的大小达到10时,园丁应该切割一段(然后他将其大小缩小到初始水平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 我一般都知道同步的基础 - 同步方法/块,锁,等待和通知方法,但这次我完全不知道该怎么做:( 它就像可怕的僵局!当然,我不希望被骗用。任何类型的提示也会非常有用。提前谢谢你,祝你有美好的一天!
答案 0 :(得分:1)
关于该队列。您可以使用ExecutorService
。
让对冲增长
所以,让你有一个可以成长和削减的对冲。
class Hedge {
private AtomicInteger height = new AtomicInteger(1);
public int grow() {
return height.incrementAndGet();
}
public int cut() {
return height.decrementAndGet();
}
}
然后你有一个让对冲成长的环境。这将模拟树篱部分;每个环境仅负责其中一个部分。当套期保值规模消失时,它也会通知Consumer<Integer>
。
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
可以在部分成长后通知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
,因为它可能会在同一时间增长并被削减,因为这种情况发生在不同的线程中。
答案 1 :(得分: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
实现
请注意,我对线程的体验有限。我希望其他用户评论并提出改进建议。