由买买提看人间百态

boards

本页内容为未名空间相应帖子的节选和存档,一周内的贴子最多显示50字,超过一周显示500字 访问原贴
JobHunting版 - Java编程讨论:LinkedIn的H2O
相关主题
java concurrence 例子关于死锁疑问
Java concurrency 面试题实现一个 thread-safe blocking queue这题怎么写啊?L家的常考
一道多线程的面试题Linked电面分享,挺好的题 应该已挂
LinkedIn 面经请教银行系统设计题,请看我写的code
怎么练习multi-threading,平常工作都是用Java框架请教L家生成H2O水分子的题。
Amazon一道synchronization的面试题concurrency应该怎么复习
问个thread synchronization的问题如何处理多用户同时调用方法修改数据库
求问一道multithreading问题L 家面经
相关话题的讨论汇总
话题: thread话题: public话题: void话题: threadinfo
进入JobHunting版参与讨论
1 (共1页)
m*****n
发帖数: 204
1
原题见http://www.mitbbs.com/article_t/JobHunting/32331973.html
这道题不是单纯作对就好的。那里贴出的解法有些值得商榷的地方。我这里谈谈个人见
解供大家参考。
从Java的角度看这道题可以有三个考点:
对Java Synchronization and Concurrency的掌握
基本的Coding Style,要能扩展,不能写spaghetti code
有把握的话可以讨论一下Lock Free Synchronization. 这题理论上只用AtomicInteger
也行。
看到这道题之后首先应该和面试者交流一下,看是否一定要用synchronized-wait-
notify. 如果不要求就不要用了,用这个既花时间又容易出错,还显得不够up to date
。当然有人可能觉得这个考基本功非要你用那也没办法。
我的基本思路是:
- 用synchronousQueue去Block and release caller threads
- 用AtomicInterger计数
- Thread Synchronization下面再提。
- 扩展性通过把H和O抽象化来实现。
作concurrency的题要照顾到四点:
- 正确性的两点:有没有race,有没有deadlock
- 效率:有没有不必要的synchronization
- 公平:先来后到怎么处理。要求高的要FIFO,低的只要没有starvation就行。
这题最省事的就是加一个control thread。Caller和controller之间一个Semaphore就
够了,而且可以很好地照顾到公平。
如果不能有自己的Thread,那么中规中矩的办法就是用Lock。别的思路我也没有了。
下面贴几段Code。
第一段是helper,把计数和Thread Enqueue/Dequeue等等都包括了。因为要照顾下面最
复杂的解法,有的Code在其他地方可以去掉。
后面有三个例子:
- 用control thread
- 无extra thread用lock
- 无extra thread也不用lock。这个可以显示一下技能,但是没有什么实际意义。
后两个解法share一个bug,但是懒得改了:releaseAll()不应该简单地loop过去。对
caller自己的element应该挑出来最后call.而且releaseAll()在用Lock的解法里应该挪
到locked region之外。
m*****n
发帖数: 204
2

public class ElementsImpl implements IElements {

private final int batchSize;
private final AtomicInteger counter = new AtomicInteger();

ElementsImpl(int i) {
batchSize = i;
}

public int getBatchSize() {
return batchSize;
}
@Override
public void inc() {
counter.incrementAndGet();
}
@Override
public boolean reserve() {
int val = counter.get();
return val >= batchSize && counter.compareAndSet(val, val -
batchSize);
}
@Override
public void cancel() {
counter.addAndGet(batchSize);
}
@Override
public void releaseQueued(SynchronousQueue queue,
boolean coversSelf) {
for (int i = 0; i < (!coversSelf? batchSize : batchSize - 1); i+
+) {
try {
queue.take();
} catch (InterruptedException ie) {
// Bug!
}
}
if (!coversSelf) {
return;
}
// Starvation prevention: should I wait or go?
if (queue.poll() != null) {
this.enqueue(queue);
}
// Otherwise I'm the last one and should go.
}
@Override
public void enqueue(SynchronousQueue queue) {
queue.offer(this);
}


}

public static enum WaterElements {
H(2), O(1);

private final IElements ele;
private WaterElements(int atomCount) {
this.ele = new ElementsImpl(atomCount);
}

public void inc() {
ele.inc();
}
public boolean reserve() {
return ele.reserve();
}
public void cancel() {
ele.cancel();
}
public void releaseQueued(WaterElements caller) {
ele.releaseQueued(waitQueue, caller == this);
}
public void enqueue() {
ele.enqueue(waitQueue);
}

private static final SynchronousQueue waitQueue =
new SynchronousQueue(true);

public static final int totalAtomsPerMolecule;

static {
int sum = 0;
for (WaterElements we : WaterElements.values()) {
sum += we.ele.getBatchSize();
}
totalAtomsPerMolecule = sum;
}

public static WaterElements reserveAll() {
for (WaterElements we : WaterElements.values()) {
if (!we.reserve()) return we;
}
return null;
}

public static void releaseAll(WaterElements caller) {
for (WaterElements we : WaterElements.values()) {
we.releaseQueued(caller); }
}

public static void cancelAll(WaterElements reserveFailure) {
WaterElements[] values = WaterElements.values();
for (int i = reserveFailure.ordinal() - 1; i >= 0; i--) {
values[i].cancel();
}
}
}
m*****n
发帖数: 204
3
package test;
import java.util.concurrent.Semaphore;
import test.IElements.WaterElements;
public class H2OExtraThread {
private final Semaphore sema = new Semaphore(0);

private volatile boolean isRunning = true;

// Called by the control thread
private void controllerRun() {

while (isRunning) {
try {
sema.acquire(WaterElements.totalAtomsPerMolecule);
} catch (InterruptedException e) {
continue;
}
WaterElements failedAt = WaterElements.reserveAll();

if (failedAt == null) {
// Success
WaterElements.releaseAll(null);
} else {
WaterElements.cancelAll(failedAt);
sema.release(WaterElements.totalAtomsPerMolecule);
}
}

}
// Invoked by external caller.
public void addO() {
WaterElements.O.inc();
sema.release(1);
WaterElements.O.enqueue();
}

// Invoked by external caller
public void addH() {
WaterElements.H.inc();
sema.release(1);
WaterElements.H.enqueue();
}
}
m*****n
发帖数: 204
4
package test;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import test.IElements.WaterElements;
public class H2OWithLock {

private Lock lock = new ReentrantLock();

public void addO() {
WaterElements.O.inc();
checkMolecule(WaterElements.O);
}

private void checkMolecule(WaterElements we) {
lock.lock();
boolean shouldBlock = false;
try {
WaterElements failedAt = WaterElements.reserveAll();

if (failedAt == null) {
WaterElements.releaseAll(we);
} else {
WaterElements.cancelAll(failedAt);
shouldBlock = true;
}
} finally {
lock.unlock();
}
if (shouldBlock) {
we.enqueue();
}
}
}
m*****n
发帖数: 204
5
package test;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import test.IElements.WaterElements;
public class H2OLockFree {
private final AtomicLong sequencer = new AtomicLong();
private final AtomicInteger contention = new AtomicInteger();
public void addO() {
addElements(WaterElements.O);
}

private void addElements(WaterElements ele) {
long id = sequencer.incrementAndGet();
contention.incrementAndGet();
ele.inc();
while (true) {
WaterElements failure = null;
next_ele:
for (WaterElements e : WaterElements.values()) {
while (id == sequencer.get() && contention.get() > 1) {
if (e.reserve()) continue next_ele;
try { Thread.sleep(1); } catch (Exception err) {}
}
failure = e;
break;
}

if (failure == null) {
// Success
WaterElements.releaseAll(ele);
contention.decrementAndGet();
} else {
// Failure
WaterElements.cancelAll(failure);
contention.decrementAndGet();
ele.enqueue();
}
}
}

}
c********t
发帖数: 5706
6
多谢!这么好的帖子,先mark后看。

AtomicInteger
date

【在 m*****n 的大作中提到】
: 原题见http://www.mitbbs.com/article_t/JobHunting/32331973.html
: 这道题不是单纯作对就好的。那里贴出的解法有些值得商榷的地方。我这里谈谈个人见
: 解供大家参考。
: 从Java的角度看这道题可以有三个考点:
: 对Java Synchronization and Concurrency的掌握
: 基本的Coding Style,要能扩展,不能写spaghetti code
: 有把握的话可以讨论一下Lock Free Synchronization. 这题理论上只用AtomicInteger
: 也行。
: 看到这道题之后首先应该和面试者交流一下,看是否一定要用synchronized-wait-
: notify. 如果不要求就不要用了,用这个既花时间又容易出错,还显得不够up to date

f*******t
发帖数: 7549
7
这个要认真看
c********t
发帖数: 5706
8
lz能否把IElements interface的codes也发一下。

【在 m*****n 的大作中提到】
: package test;
: import java.util.concurrent.atomic.AtomicInteger;
: import java.util.concurrent.atomic.AtomicLong;
: import test.IElements.WaterElements;
: public class H2OLockFree {
: private final AtomicLong sequencer = new AtomicLong();
: private final AtomicInteger contention = new AtomicInteger();
: public void addO() {
: addElements(WaterElements.O);
: }

c********t
发帖数: 5706
9
在无extra thread的情况下,我也觉得应该可以只用atomicInteger的。可是我写不出
,只写出用lock condition的。
能不能说说,你为什么说这题“理论上”只用AtomicInteger也行?

AtomicInteger
date

【在 m*****n 的大作中提到】
: 原题见http://www.mitbbs.com/article_t/JobHunting/32331973.html
: 这道题不是单纯作对就好的。那里贴出的解法有些值得商榷的地方。我这里谈谈个人见
: 解供大家参考。
: 从Java的角度看这道题可以有三个考点:
: 对Java Synchronization and Concurrency的掌握
: 基本的Coding Style,要能扩展,不能写spaghetti code
: 有把握的话可以讨论一下Lock Free Synchronization. 这题理论上只用AtomicInteger
: 也行。
: 看到这道题之后首先应该和面试者交流一下,看是否一定要用synchronized-wait-
: notify. 如果不要求就不要用了,用这个既花时间又容易出错,还显得不够up to date

w********p
发帖数: 948
10
收藏。等以后看。
相关主题
Amazon一道synchronization的面试题关于死锁疑问
问个thread synchronization的问题实现一个 thread-safe blocking queue这题怎么写啊?L家的常考
求问一道multithreading问题Linked电面分享,挺好的题 应该已挂
进入JobHunting版参与讨论
v***n
发帖数: 562
11
好贴啊!
F****n
发帖数: 3271
12
public class H2O {
public static class ThreadHolder {
Thread thread;
ThreadHolder(Thread thread) {
this.thread = thread;
}
}
protected LinkedList hlist = new LinkedList();
protected LinkedList olist = new LinkedList();
public boolean h() {
ThreadHolder current = new ThreadHolder(Thread.currentThread());
synchronized (current) {
ThreadHolder[] threadsToWakeUp = null;
// updating the queues requires a global lock;
synchronized (this) {
this.hlist.add(current);
threadsToWakeUp = this.getThreadsToWakeUp();
}
// now the wait and wake up is only in the current lock;
boolean notInterrupted = this
.checkWaitAndWakeUp(current, threadsToWakeUp);
if (notInterrupted) {
this.doH();
}
return notInterrupted;
}
}
private ThreadHolder[] getThreadsToWakeUp() {
if (this.hlist.size() >= 2 && this.olist.size() >= 1) {
ThreadHolder[] holders = new ThreadHolder[3];
holders[0] = this.hlist.poll();
holders[1] = this.hlist.poll();
holders[2] = this.olist.poll();
return holders;
}
return null;
}
// return true if the wait is not interrupted.
private boolean checkWaitAndWakeUp(ThreadHolder current,
ThreadHolder[] threadsToWakeUp) {
boolean wait = true;
if (threadsToWakeUp != null) {
for (ThreadHolder threadToWakeUp : threadsToWakeUp) {
if (threadToWakeUp == current) {
wait = false;
} else {
// this lock ensures notify will only happen after the
// thread wait;
synchronized (threadToWakeUp) {
threadToWakeUp.notifyAll();
}
}
}
}
if (wait) {
try {
current.wait();
} catch (InterruptedException e) {
return false;
}
}
return true;
}
// similiar to h();
public boolean o() {
ThreadHolder current = new ThreadHolder(Thread.currentThread());
synchronized (current) {
ThreadHolder[] threadsToWakeUp = null;
// updating the queues requires a global lock;
synchronized (this) {
this.olist.add(current);
threadsToWakeUp = this.getThreadsToWakeUp();
}
// now the wait and wake up is only in the current lock;
boolean notInterrupted = this
.checkWaitAndWakeUp(current, threadsToWakeUp);
if (notInterrupted) {
this.doO();
}
return notInterrupted;
}
}
// Override this to extend the business logic
protected void doH() {
// business logic;
}
// Override this to extend the business logic
protected void doO() {
// business logic
}
}

AtomicInteger
date

【在 m*****n 的大作中提到】
: 原题见http://www.mitbbs.com/article_t/JobHunting/32331973.html
: 这道题不是单纯作对就好的。那里贴出的解法有些值得商榷的地方。我这里谈谈个人见
: 解供大家参考。
: 从Java的角度看这道题可以有三个考点:
: 对Java Synchronization and Concurrency的掌握
: 基本的Coding Style,要能扩展,不能写spaghetti code
: 有把握的话可以讨论一下Lock Free Synchronization. 这题理论上只用AtomicInteger
: 也行。
: 看到这道题之后首先应该和面试者交流一下,看是否一定要用synchronized-wait-
: notify. 如果不要求就不要用了,用这个既花时间又容易出错,还显得不够up to date

m*****n
发帖数: 204
13
纯Busy wait不主动yield, progress 不容易把握。

【在 c********t 的大作中提到】
: 在无extra thread的情况下,我也觉得应该可以只用atomicInteger的。可是我写不出
: ,只写出用lock condition的。
: 能不能说说,你为什么说这题“理论上”只用AtomicInteger也行?
:
: AtomicInteger
: date

f********d
发帖数: 51
14
如果允许我大展身手的话。我会用EIP Aggregator pattern
http://www.eaipatterns.com/Aggregator.html
如果要考我java,我就用 new concurrent package, 简单明了
public class H2O {
private BlockingQueue hq = Queues.newArrayBlockingQueue();
private BlockingQueue oq = Queues.newArrayBlockingQueue();
public H2O H() {
CountDownLatch latch = new CountDownLatch(1);
hq.add(latch);
latch.await();
return this;
}
public H2O O() {
CountDownLatch latch = new CountDownLatch(1);
oq.add(latch);
latch.await();
return this;
}
public H2O() {
Executors.newSingleThreadPool().execute(new Runnable() {
void run() {
while(true) {
CountDownLatch o = oq.take();
CountDownLatch h1 =hq.take();
hq.take().countDown();
h1.countDown();
o.countDown();
}
}
}
}
}
f********d
发帖数: 51
15
没有额外thread的版本
public class H2O {
private BlockingQueue hq = Queues.newArrayBlockingQueue();
public H2O H() {
CountDownLatch latch = new CountDownLatch(1);
hq.add(latch);
latch.await();
return this;
}
public H2O O() {
// this while is to make sure there is no such case where
// one O got one H and then being prempted, another O got the new H
// above situation will result 2O and 2H produces no H2O
while(true) {
CountDownLatch first = hq.take();
CountDownLatch second = hq.poll();
if (second == null) {
hq.add(first);
continue;
}
first.countDown();
second.countDown();
return this;
}
}
}
f********d
发帖数: 51
16
in a concurrent implementation, Thread.sleep is always a big NONO

【在 m*****n 的大作中提到】
: package test;
: import java.util.concurrent.atomic.AtomicInteger;
: import java.util.concurrent.atomic.AtomicLong;
: import test.IElements.WaterElements;
: public class H2OLockFree {
: private final AtomicLong sequencer = new AtomicLong();
: private final AtomicInteger contention = new AtomicInteger();
: public void addO() {
: addElements(WaterElements.O);
: }

f********d
发帖数: 51
17
另外一个思路如果你面试的是hedge fund,会给你大加分
http://en.wikipedia.org/wiki/Reactive_programming
用reactive programing来解决dependency calculation
f********d
发帖数: 51
18
这种题还有比较重要的是unit test,怎么在unit test模拟multi threading 的多种可
能出现的情况。
怎么assert
F****n
发帖数: 3271
19
你的都不对,
LZ的把简单问题复杂化了
要用java.util.concurrent这题其实很简单
一个ReentrantLock 两个Condition就行了

);

【在 f********d 的大作中提到】
: 没有额外thread的版本
: public class H2O {
: private BlockingQueue hq = Queues.newArrayBlockingQueue();
: public H2O H() {
: CountDownLatch latch = new CountDownLatch(1);
: hq.add(latch);
: latch.await();
: return this;
: }
: public H2O O() {

f********d
发帖数: 51
20
I've passed the unit tests pretty well in different scenarios.
of course you can use ReentrantLock and 2 Conditions. And you need one more
thing which is the CyclicBarrier for the H(2)
Problem came when you implement.
When O came, you normally will signal the Condition for O. but what if there
's no H came before or only one came?
Now you need to await on H's condition.
Now you meet a pretty weird situation of signal first or await first.
normally the strategy to solve is using while(true) and keep trying to avoid
deadlocks.
That's fine the code can work. but can you think of any better way of
handling this and how can it be extended in the future?
First thing come into mind is, why I need that while(true)? because I dont
know whether the other side is waiting by Condition interface. What about
introduce one?
alright, now since you need a collection, what about a concurrent one to
help? BlockingQueue came into the door.
Now i still need condition to do await. now you could do lock and new
condition and await. but the question is, is there any class can do this job
much easier?
That's where the CountDownLatch kicks in.
okay, now back to the extensible question? what if you have C2H4O2? then you
code is pretty messy. using the first approach i gave.
in the process method, The runnable is actually describing how H2O or C2H4O2
. and you could make it better as a DSL and encapsulate and abstract to
Element and ElementDefintion.
in that way, you can loop thru all the ElementDefitions(a formula). now the
constructor can take a DSL of ElementDefinition.
Now to this point, it becomes a trival version of Aggregator in Camel or
Spring integration. now what's left over?
of course, Exception handlings.
There will be more considierations on that front, but this is also a test to
see how sophisticated the interviewee is.
btw, I used the same questioin in my interviews. very few people can go this
far.
相关主题
请教银行系统设计题,请看我写的code如何处理多用户同时调用方法修改数据库
请教L家生成H2O水分子的题。L 家面经
concurrency应该怎么复习面试时候差点想直接推门走,真有这感觉!
进入JobHunting版参与讨论
f********d
发帖数: 51
21
while(true) {
CountDownLatch o = oq.take(); // take an O
CountDownLatch h1 =hq.take(); // take an H
hq.take().countDown(); // take another H
h1.countDown(); // count down all the rest
o.countDown();
}
any new formula, you only need to make sure the first 3 lines reflects your
formula well. it becomes very extensible. and you can also do
Collection list = Lists.newArrayList();
for (ElementDefinition ed : defs) {
BlockingQueue queue = ed.getQueue();
for (int i =0; i < ed.getNumber() ; i++) {
list.add(queue.take());
}
}
for (CountDownLAtch latch : list) {
latch.countDown();
}
with DSL, you could
val H2 = new ElementDefinition(2);
val O = new ElementDefinition(1);
defs.add(H2);
defs.add(O);
void H() {
H2.await();
}
class ElementDefinition {
....
public void await() {
CountDownLatch latch = new CountDownLatch(1);
queue.add(latch);
latch.await();
}
....
}
this is synchronized implementaiton. you can also have interface Element to
replace CountDownLAtch.
for synchronized implementation, use ElementSychImpl with CountDownLatch.
for asycn, get a call back.
Now the codes will be quite extensible and easier to understand

more
there
avoid

【在 f********d 的大作中提到】
: I've passed the unit tests pretty well in different scenarios.
: of course you can use ReentrantLock and 2 Conditions. And you need one more
: thing which is the CyclicBarrier for the H(2)
: Problem came when you implement.
: When O came, you normally will signal the Condition for O. but what if there
: 's no H came before or only one came?
: Now you need to await on H's condition.
: Now you meet a pretty weird situation of signal first or await first.
: normally the strategy to solve is using while(true) and keep trying to avoid
: deadlocks.

i*******6
发帖数: 107
22
My 5 cents:
import java.util.concurrent.*;
class MyO implements Runnable{
int index;
CountDownLatch lock;
public MyO (int index, CountDownLatch lock) {
this.index = index;
this.lock = lock;
}
public void run() {
try {
Thread.sleep((long) (Math.random() * 1000));
lock.await();
System.out.println("Take O:" + index + " to form an H2O!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
class MyH implements Runnable{
int index;
CountDownLatch lock;
public MyH(int index, CountDownLatch lock) {
this.index = index;
this.lock = lock;
}
public void run() {
try {
hread.sleep((long) (Math.random() * 1000));
lock.await();
System.out.println("take H:"+index+" to form a H2O!");
} catch(Exception e) {
e.printStackTrace();
}
}
}
public class MyH2O {
private static BlockingQueue hq = new
LinkedBlockingQueue();
private static BlockingQueue oq = new
LinkedBlockingQueue();
public static void main(String args[]){
ExecutorService service = Executors.newCachedThreadPool();
service.submit(new Thread() {
public void run(){
try{
while (true) {
Thread.sleep((long) (Math.random() * 1000));
CountDownLatch firstH = hq.take();
CountDownLatch secondH = hq.poll();
CountDownLatch firstO = oq.take();
if (secondH == null) {
hq.add(firstH);
continue;
}
firstH.countDown();
secondH.countDown();
firstO.countDown();
System.out.println("A H2O created!");
break;
}
} catch(Exception e) {
e.printStackTrace();
}
}
});
for (int i=0;i<100;i++) {
CountDownLatch lock = new CountDownLatch(1);
int type = (int)(Math.random()*2);
if (type == 0){
hq.add(lock);
service.submit(new MyH(i+1,lock));
} else {
oq.add(lock);
service.submit(new MyO(i+1,lock));
}
}
service.shutdown();
}
}
n********r
发帖数: 102
23
mark一下。。学习了
m*****n
发帖数: 204
24
我对CountDownLatch没太多想过。学习了。

);
);

【在 f********d 的大作中提到】
: 如果允许我大展身手的话。我会用EIP Aggregator pattern
: http://www.eaipatterns.com/Aggregator.html
: 如果要考我java,我就用 new concurrent package, 简单明了
: public class H2O {
: private BlockingQueue hq = Queues.newArrayBlockingQueue();
: private BlockingQueue oq = Queues.newArrayBlockingQueue();
: public H2O H() {
: CountDownLatch latch = new CountDownLatch(1);
: hq.add(latch);
: latch.await();

z*******3
发帖数: 13709
25
原题:
3: 实现两个函数: H() and O(), 这两个函数会被多线程调用。当一个线程调用H或O时
,如果当前已经有至少两个线程call H和一个线程call O。那么让两个call H和一个
call O的线程返回(产生一个水分子),其他的都block。
我随手写了一个,不想用synchronized关键字
这个要搞起来的确比较麻烦,想上java.util.concurrent
研究了一下copyonwritearraylist,还是不行,两个方法都得上synchronized
List l = new ArrayList();
public synchronized void h(){
if(l.size()>=2){
Thread hThread = l.get(0);
Thread oThread = l.get(l.size()-1);
if(hThread.isH() && oThread.isO()){
hThread.notify();
oThread.notify();
return;
}
}
Thread currentThread = Thread.getCurrentThread();
l.add(0,currentThread);
currentThread.wait();
}
public synchronized void o(){
if(l.size()>=2){
Thread hThread1 = l.get(0);
Thread hThread2 = l.get(1);
if(hThread1.isH() && hThread2.isH()){
hThread1.notify();
hThread2.notify();
return;
}
}
Thread currentThread = Thread.getCurrentThread();
l.add(currentThread);
currentThread.wait();
}
z*******3
发帖数: 13709
26
isH()和isO()要扩展一下,要额外加一个类
包装thread对象以及该thread读取的是o还是h
要不然thread本身是没有这个方法的
class ThreadInfo{
private Thread thread;
private boolean isH;
//setter/getter method
...
}
然后把l里面保存的全部换成ThreadInfo对象
z*******3
发帖数: 13709
27
或者找个map寄存
不过增加的map自然增加了查找的时间
效率上不如包装类
List l= new ArrayList();
Map m= new HashMap();
public synchronized void h(){
if(l.size()>=2){
Thread hThread = l.get(0);
Thread oThread = l.get(l.size()-1);
if(m.get(hThread) && !m.get(oThread)){
hThread.notify();
oThread.notify();
return;
}
}
Thread currentThread = Thread.getCurrentThread();
l.add(0,currentThread);
m.put(currentThead, true);
currentThread.wait();
}
public synchronized void o(){
if(l.size()>=2){
Thread hThread1 = l.get(0);
Thread hThread2 = l.get(1);
if(m.get(hThread1) && m.get(hThread2)){
hThread1.notify();
hThread2.notify();
return;
}
}
Thread currentThread = Thread.getCurrentThread();
l.add(currentThread);
m.put(currentThread, false);
currentThread.wait();
}
z*******3
发帖数: 13709
28
汗,实验了一下,有三个小问题,看来多线程白板还是难以bug free,需要多练习
getCurrentThread() -> currentThread()
currentThread.wait() -> wait()
hThread.notify() -> synchronized(hThread){ hThread.notify();}
z*******3
发帖数: 13709
29
List l = new ArrayList();

public synchronized void h() throws InterruptedException {
if (l.size() >= 2) {
ThreadInfo hThread = l.get(0);
ThreadInfo oThread = l.get(l.size() - 1);
if (hThread.isH() && oThread.isO()) {
synchronized(hThread){hThread.notify();}
synchronized(oThread){oThread.notify();}
l.remove(hThread);
l.remove(oThread);
return;
}
}
Thread currentThread = Thread.currentThread();
ThreadInfo ti = new ThreadInfo();
ti.setH(true);
ti.setT(currentThread);
l.add(0, ti);
wait();
}
public synchronized void o() throws InterruptedException {
if (l.size() >= 2) {
ThreadInfo hThread1 = l.get(0);
ThreadInfo hThread2 = l.get(1);
if (hThread1.isH() && hThread2.isH()) {
synchronized(hThread1){hThread1.notify();}
synchronized(hThread2){hThread2.notify();}
l.remove(hThread1);
l.remove(hThread2);
return;
}
}
Thread currentThread = Thread.currentThread();
ThreadInfo ti = new ThreadInfo();
ti.setH(false);
ti.setT(currentThread);
l.add(ti);
wait();
}
F****n
发帖数: 3271
30
不太对,
你的wait没有notify
而且h()和o()都全部synchronized
只用synchronized的解法我前面写过。

【在 z*******3 的大作中提到】
: List l = new ArrayList();
:
: public synchronized void h() throws InterruptedException {
: if (l.size() >= 2) {
: ThreadInfo hThread = l.get(0);
: ThreadInfo oThread = l.get(l.size() - 1);
: if (hThread.isH() && oThread.isO()) {
: synchronized(hThread){hThread.notify();}
: synchronized(oThread){oThread.notify();}
: l.remove(hThread);

相关主题
想问一下那道H2O的多线程题Java concurrency 面试题
面试的时候让你写一个thread pool,能写正确的来举手一道多线程的面试题
java concurrence 例子LinkedIn 面经
进入JobHunting版参与讨论
z*******3
发帖数: 13709
31
行不行直接开几个thread跑一下不就知道了
notify在中间
一旦执行notify就会return,不再执行wait
一旦执行wait,就压入l等待其他thread notify
并不是所有的thread都需要压入list
只要条件合适,有足够的h和o在list里面,就不需要压入,直接跑完线程
而且计算l.size()的mean应该在4左右
hhhhhhhhhh或者oooooooh的概率极低
大多数时候是hhhh或者oooh甚至更短,hh的来个o就清零了
这种长度还当成大list来做java.util.concurrent就搞笑了

【在 F****n 的大作中提到】
: 不太对,
: 你的wait没有notify
: 而且h()和o()都全部synchronized
: 只用synchronized的解法我前面写过。

F****n
发帖数: 3271
32
你知道你的hThread.notify() notify不到 wait()把???

【在 z*******3 的大作中提到】
: 行不行直接开几个thread跑一下不就知道了
: notify在中间
: 一旦执行notify就会return,不再执行wait
: 一旦执行wait,就压入l等待其他thread notify
: 并不是所有的thread都需要压入list
: 只要条件合适,有足够的h和o在list里面,就不需要压入,直接跑完线程
: 而且计算l.size()的mean应该在4左右
: hhhhhhhhhh或者oooooooh的概率极低
: 大多数时候是hhhh或者oooh甚至更短,hh的来个o就清零了
: 这种长度还当成大list来做java.util.concurrent就搞笑了

z*******3
发帖数: 13709
33
而且我看了下,原来设计,没有循环语句
也就是说,无论l.size怎么变
执行的效率都是一样的,复杂度是O(1)常量
那这个时候做多线程的优化就没有必要了
完全可以把那一小段当成原子操作来执行
反正每次执行就那么点时间,无所谓
另外也没有侵入他人代码,不改写Thread之类的
更没有sleep这种可怕的方法,蛮好
z*******3
发帖数: 13709
34
我都说了,你自己写个main试试不就知道了?

【在 F****n 的大作中提到】
: 你知道你的hThread.notify() notify不到 wait()把???
F****n
发帖数: 3271
35
你就解释一下为啥hThread.notify()能影响wait()吧

【在 z*******3 的大作中提到】
: 我都说了,你自己写个main试试不就知道了?
z****e
发帖数: 54598
36
因为wait的monitor在l上,而不是在ti上
这个问题可以单独剥离出来看,如果写成一堆的话
那就非常不容易阅读了,这是代码
List l = new ArrayList();

public void h() throws InterruptedException {
ThreadInfo ti =null;

synchronized(l){
if (l.size() >= 2) {
ThreadInfo hThread = l.get(0);
ThreadInfo oThread = l.get(l.size() - 1);
if (hThread.isH() && oThread.isO()) {
synchronized(hThread){
hThread.notified();
hThread.notify();
}
synchronized(oThread){
oThread.notified();
oThread.notify();
}
l.remove(hThread);
l.remove(oThread);
System.out.println("1 h2o");
return;
}
}
Thread currentThread = Thread.currentThread();
ti = new ThreadInfo();
ti.setH(true);
ti.setT(currentThread);
l.add(0, ti);
}
synchronized(ti){
if(ti!=null && !ti.isNotified())
ti.wait();
}
}
public void o() throws InterruptedException {
ThreadInfo ti =null;
synchronized(l){
if (l.size() >= 2) {
ThreadInfo hThread1 = l.get(0);
ThreadInfo hThread2 = l.get(1);
if (hThread1.isH() && hThread2.isH()) {
synchronized(hThread1){
hThread1.notified();
hThread1.notify();
}
synchronized(hThread2){
hThread2.notified();
hThread2.notify();
}
l.remove(hThread1);
l.remove(hThread2);
System.out.println("1 h2o");
return;
}
}
Thread currentThread = Thread.currentThread();
ti = new ThreadInfo();
ti.setH(false);
ti.setT(currentThread);
l.add(ti);
}

synchronized(ti){
if(ti!=null && !ti.isNotified())
ti.wait();
}
}
-----------------------------
测试结果
o
h
o
h
1 h2o
end .......,Thread[Thread-5,5,main]
end .......,Thread[Thread-3,5,main]
end .......,Thread[Thread-4,5,main]
h
h
1 h2o
end .......,Thread[Thread-2,5,main]
end .......,Thread[Thread-6,5,main]
end .......,Thread[Thread-1,5,main]
-------------------------------
class ThreadInfo{
private boolean isNotified=false;
private Thread t;
private boolean isH;
public Thread getT() {
return t;
}
public void setT(Thread t) {
this.t = t;
}
public boolean isH() {
return isH;
}
public void setH(boolean isH) {
this.isH = isH;
}

public boolean isO() {
return !isH();
}

public void notified(){
this.isNotified = true;
}

public boolean isNotified(){
return this.isNotified;
}
}

【在 F****n 的大作中提到】
: 你就解释一下为啥hThread.notify()能影响wait()吧
F****n
发帖数: 3271
37
wait(); 的 monitor 怎么会在 l 上?
wait(); <=> this.wait();

【在 z****e 的大作中提到】
: 因为wait的monitor在l上,而不是在ti上
: 这个问题可以单独剥离出来看,如果写成一堆的话
: 那就非常不容易阅读了,这是代码
: List l = new ArrayList();
:
: public void h() throws InterruptedException {
: ThreadInfo ti =null;
:
: synchronized(l){
: if (l.size() >= 2) {

m*****n
发帖数: 204
38
原题见http://www.mitbbs.com/article_t/JobHunting/32331973.html
这道题不是单纯作对就好的。那里贴出的解法有些值得商榷的地方。我这里谈谈个人见
解供大家参考。
从Java的角度看这道题可以有三个考点:
对Java Synchronization and Concurrency的掌握
基本的Coding Style,要能扩展,不能写spaghetti code
有把握的话可以讨论一下Lock Free Synchronization. 这题理论上只用AtomicInteger
也行。
看到这道题之后首先应该和面试者交流一下,看是否一定要用synchronized-wait-
notify. 如果不要求就不要用了,用这个既花时间又容易出错,还显得不够up to date
。当然有人可能觉得这个考基本功非要你用那也没办法。
我的基本思路是:
- 用synchronousQueue去Block and release caller threads
- 用AtomicInterger计数
- Thread Synchronization下面再提。
- 扩展性通过把H和O抽象化来实现。
作concurrency的题要照顾到四点:
- 正确性的两点:有没有race,有没有deadlock
- 效率:有没有不必要的synchronization
- 公平:先来后到怎么处理。要求高的要FIFO,低的只要没有starvation就行。
这题最省事的就是加一个control thread。Caller和controller之间一个Semaphore就
够了,而且可以很好地照顾到公平。
如果不能有自己的Thread,那么中规中矩的办法就是用Lock。别的思路我也没有了。
下面贴几段Code。
第一段是helper,把计数和Thread Enqueue/Dequeue等等都包括了。因为要照顾下面最
复杂的解法,有的Code在其他地方可以去掉。
后面有三个例子:
- 用control thread
- 无extra thread用lock
- 无extra thread也不用lock。这个可以显示一下技能,但是没有什么实际意义。
后两个解法share一个bug,但是懒得改了:releaseAll()不应该简单地loop过去。对
caller自己的element应该挑出来最后call.而且releaseAll()在用Lock的解法里应该挪
到locked region之外。
m*****n
发帖数: 204
39

public class ElementsImpl implements IElements {

private final int batchSize;
private final AtomicInteger counter = new AtomicInteger();

ElementsImpl(int i) {
batchSize = i;
}

public int getBatchSize() {
return batchSize;
}
@Override
public void inc() {
counter.incrementAndGet();
}
@Override
public boolean reserve() {
int val = counter.get();
return val >= batchSize && counter.compareAndSet(val, val -
batchSize);
}
@Override
public void cancel() {
counter.addAndGet(batchSize);
}
@Override
public void releaseQueued(SynchronousQueue queue,
boolean coversSelf) {
for (int i = 0; i < (!coversSelf? batchSize : batchSize - 1); i+
+) {
try {
queue.take();
} catch (InterruptedException ie) {
// Bug!
}
}
if (!coversSelf) {
return;
}
// Starvation prevention: should I wait or go?
if (queue.poll() != null) {
this.enqueue(queue);
}
// Otherwise I'm the last one and should go.
}
@Override
public void enqueue(SynchronousQueue queue) {
queue.offer(this);
}


}

public static enum WaterElements {
H(2), O(1);

private final IElements ele;
private WaterElements(int atomCount) {
this.ele = new ElementsImpl(atomCount);
}

public void inc() {
ele.inc();
}
public boolean reserve() {
return ele.reserve();
}
public void cancel() {
ele.cancel();
}
public void releaseQueued(WaterElements caller) {
ele.releaseQueued(waitQueue, caller == this);
}
public void enqueue() {
ele.enqueue(waitQueue);
}

private static final SynchronousQueue waitQueue =
new SynchronousQueue(true);

public static final int totalAtomsPerMolecule;

static {
int sum = 0;
for (WaterElements we : WaterElements.values()) {
sum += we.ele.getBatchSize();
}
totalAtomsPerMolecule = sum;
}

public static WaterElements reserveAll() {
for (WaterElements we : WaterElements.values()) {
if (!we.reserve()) return we;
}
return null;
}

public static void releaseAll(WaterElements caller) {
for (WaterElements we : WaterElements.values()) {
we.releaseQueued(caller); }
}

public static void cancelAll(WaterElements reserveFailure) {
WaterElements[] values = WaterElements.values();
for (int i = reserveFailure.ordinal() - 1; i >= 0; i--) {
values[i].cancel();
}
}
}
m*****n
发帖数: 204
40
package test;
import java.util.concurrent.Semaphore;
import test.IElements.WaterElements;
public class H2OExtraThread {
private final Semaphore sema = new Semaphore(0);

private volatile boolean isRunning = true;

// Called by the control thread
private void controllerRun() {

while (isRunning) {
try {
sema.acquire(WaterElements.totalAtomsPerMolecule);
} catch (InterruptedException e) {
continue;
}
WaterElements failedAt = WaterElements.reserveAll();

if (failedAt == null) {
// Success
WaterElements.releaseAll(null);
} else {
WaterElements.cancelAll(failedAt);
sema.release(WaterElements.totalAtomsPerMolecule);
}
}

}
// Invoked by external caller.
public void addO() {
WaterElements.O.inc();
sema.release(1);
WaterElements.O.enqueue();
}

// Invoked by external caller
public void addH() {
WaterElements.H.inc();
sema.release(1);
WaterElements.H.enqueue();
}
}
相关主题
LinkedIn 面经问个thread synchronization的问题
怎么练习multi-threading,平常工作都是用Java框架求问一道multithreading问题
Amazon一道synchronization的面试题关于死锁疑问
进入JobHunting版参与讨论
m*****n
发帖数: 204
41
package test;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import test.IElements.WaterElements;
public class H2OWithLock {

private Lock lock = new ReentrantLock();

public void addO() {
WaterElements.O.inc();
checkMolecule(WaterElements.O);
}

private void checkMolecule(WaterElements we) {
lock.lock();
boolean shouldBlock = false;
try {
WaterElements failedAt = WaterElements.reserveAll();

if (failedAt == null) {
WaterElements.releaseAll(we);
} else {
WaterElements.cancelAll(failedAt);
shouldBlock = true;
}
} finally {
lock.unlock();
}
if (shouldBlock) {
we.enqueue();
}
}
}
m*****n
发帖数: 204
42
package test;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import test.IElements.WaterElements;
public class H2OLockFree {
private final AtomicLong sequencer = new AtomicLong();
private final AtomicInteger contention = new AtomicInteger();
public void addO() {
addElements(WaterElements.O);
}

private void addElements(WaterElements ele) {
long id = sequencer.incrementAndGet();
contention.incrementAndGet();
ele.inc();
while (true) {
WaterElements failure = null;
next_ele:
for (WaterElements e : WaterElements.values()) {
while (id == sequencer.get() && contention.get() > 1) {
if (e.reserve()) continue next_ele;
try { Thread.sleep(1); } catch (Exception err) {}
}
failure = e;
break;
}

if (failure == null) {
// Success
WaterElements.releaseAll(ele);
contention.decrementAndGet();
} else {
// Failure
WaterElements.cancelAll(failure);
contention.decrementAndGet();
ele.enqueue();
}
}
}

}
c********t
发帖数: 5706
43
多谢!这么好的帖子,先mark后看。

AtomicInteger
date

【在 m*****n 的大作中提到】
: 原题见http://www.mitbbs.com/article_t/JobHunting/32331973.html
: 这道题不是单纯作对就好的。那里贴出的解法有些值得商榷的地方。我这里谈谈个人见
: 解供大家参考。
: 从Java的角度看这道题可以有三个考点:
: 对Java Synchronization and Concurrency的掌握
: 基本的Coding Style,要能扩展,不能写spaghetti code
: 有把握的话可以讨论一下Lock Free Synchronization. 这题理论上只用AtomicInteger
: 也行。
: 看到这道题之后首先应该和面试者交流一下,看是否一定要用synchronized-wait-
: notify. 如果不要求就不要用了,用这个既花时间又容易出错,还显得不够up to date

f*******t
发帖数: 7549
44
这个要认真看
c********t
发帖数: 5706
45
lz能否把IElements interface的codes也发一下。

【在 m*****n 的大作中提到】
: package test;
: import java.util.concurrent.atomic.AtomicInteger;
: import java.util.concurrent.atomic.AtomicLong;
: import test.IElements.WaterElements;
: public class H2OLockFree {
: private final AtomicLong sequencer = new AtomicLong();
: private final AtomicInteger contention = new AtomicInteger();
: public void addO() {
: addElements(WaterElements.O);
: }

c********t
发帖数: 5706
46
在无extra thread的情况下,我也觉得应该可以只用atomicInteger的。可是我写不出
,只写出用lock condition的。
能不能说说,你为什么说这题“理论上”只用AtomicInteger也行?

AtomicInteger
date

【在 m*****n 的大作中提到】
: 原题见http://www.mitbbs.com/article_t/JobHunting/32331973.html
: 这道题不是单纯作对就好的。那里贴出的解法有些值得商榷的地方。我这里谈谈个人见
: 解供大家参考。
: 从Java的角度看这道题可以有三个考点:
: 对Java Synchronization and Concurrency的掌握
: 基本的Coding Style,要能扩展,不能写spaghetti code
: 有把握的话可以讨论一下Lock Free Synchronization. 这题理论上只用AtomicInteger
: 也行。
: 看到这道题之后首先应该和面试者交流一下,看是否一定要用synchronized-wait-
: notify. 如果不要求就不要用了,用这个既花时间又容易出错,还显得不够up to date

w********p
发帖数: 948
47
收藏。等以后看。
v***n
发帖数: 562
48
好贴啊!
F****n
发帖数: 3271
49
public class H2O {
public static class ThreadHolder {
Thread thread;
ThreadHolder(Thread thread) {
this.thread = thread;
}
}
protected LinkedList hlist = new LinkedList();
protected LinkedList olist = new LinkedList();
public boolean h() {
ThreadHolder current = new ThreadHolder(Thread.currentThread());
synchronized (current) {
ThreadHolder[] threadsToWakeUp = null;
// updating the queues requires a global lock;
synchronized (this) {
this.hlist.add(current);
threadsToWakeUp = this.getThreadsToWakeUp();
}
// now the wait and wake up is only in the current lock;
boolean notInterrupted = this
.checkWaitAndWakeUp(current, threadsToWakeUp);
if (notInterrupted) {
this.doH();
}
return notInterrupted;
}
}
private ThreadHolder[] getThreadsToWakeUp() {
if (this.hlist.size() >= 2 && this.olist.size() >= 1) {
ThreadHolder[] holders = new ThreadHolder[3];
holders[0] = this.hlist.poll();
holders[1] = this.hlist.poll();
holders[2] = this.olist.poll();
return holders;
}
return null;
}
// return true if the wait is not interrupted.
private boolean checkWaitAndWakeUp(ThreadHolder current,
ThreadHolder[] threadsToWakeUp) {
boolean wait = true;
if (threadsToWakeUp != null) {
for (ThreadHolder threadToWakeUp : threadsToWakeUp) {
if (threadToWakeUp == current) {
wait = false;
} else {
// this lock ensures notify will only happen after the
// thread wait;
synchronized (threadToWakeUp) {
threadToWakeUp.notifyAll();
}
}
}
}
if (wait) {
try {
current.wait();
} catch (InterruptedException e) {
return false;
}
}
return true;
}
// similiar to h();
public boolean o() {
ThreadHolder current = new ThreadHolder(Thread.currentThread());
synchronized (current) {
ThreadHolder[] threadsToWakeUp = null;
// updating the queues requires a global lock;
synchronized (this) {
this.olist.add(current);
threadsToWakeUp = this.getThreadsToWakeUp();
}
// now the wait and wake up is only in the current lock;
boolean notInterrupted = this
.checkWaitAndWakeUp(current, threadsToWakeUp);
if (notInterrupted) {
this.doO();
}
return notInterrupted;
}
}
// Override this to extend the business logic
protected void doH() {
// business logic;
}
// Override this to extend the business logic
protected void doO() {
// business logic
}
}

AtomicInteger
date

【在 m*****n 的大作中提到】
: 原题见http://www.mitbbs.com/article_t/JobHunting/32331973.html
: 这道题不是单纯作对就好的。那里贴出的解法有些值得商榷的地方。我这里谈谈个人见
: 解供大家参考。
: 从Java的角度看这道题可以有三个考点:
: 对Java Synchronization and Concurrency的掌握
: 基本的Coding Style,要能扩展,不能写spaghetti code
: 有把握的话可以讨论一下Lock Free Synchronization. 这题理论上只用AtomicInteger
: 也行。
: 看到这道题之后首先应该和面试者交流一下,看是否一定要用synchronized-wait-
: notify. 如果不要求就不要用了,用这个既花时间又容易出错,还显得不够up to date

m*****n
发帖数: 204
50
纯Busy wait不主动yield, progress 不容易把握。

【在 c********t 的大作中提到】
: 在无extra thread的情况下,我也觉得应该可以只用atomicInteger的。可是我写不出
: ,只写出用lock condition的。
: 能不能说说,你为什么说这题“理论上”只用AtomicInteger也行?
:
: AtomicInteger
: date

相关主题
实现一个 thread-safe blocking queue这题怎么写啊?L家的常考请教L家生成H2O水分子的题。
Linked电面分享,挺好的题 应该已挂concurrency应该怎么复习
请教银行系统设计题,请看我写的code如何处理多用户同时调用方法修改数据库
进入JobHunting版参与讨论
f********d
发帖数: 51
51
如果允许我大展身手的话。我会用EIP Aggregator pattern
http://www.eaipatterns.com/Aggregator.html
如果要考我java,我就用 new concurrent package, 简单明了
public class H2O {
private BlockingQueue hq = Queues.newArrayBlockingQueue();
private BlockingQueue oq = Queues.newArrayBlockingQueue();
public H2O H() {
CountDownLatch latch = new CountDownLatch(1);
hq.add(latch);
latch.await();
return this;
}
public H2O O() {
CountDownLatch latch = new CountDownLatch(1);
oq.add(latch);
latch.await();
return this;
}
public H2O() {
Executors.newSingleThreadPool().execute(new Runnable() {
void run() {
while(true) {
CountDownLatch o = oq.take();
CountDownLatch h1 =hq.take();
hq.take().countDown();
h1.countDown();
o.countDown();
}
}
}
}
}
f********d
发帖数: 51
52
没有额外thread的版本
public class H2O {
private BlockingQueue hq = Queues.newArrayBlockingQueue();
public H2O H() {
CountDownLatch latch = new CountDownLatch(1);
hq.add(latch);
latch.await();
return this;
}
public H2O O() {
// this while is to make sure there is no such case where
// one O got one H and then being prempted, another O got the new H
// above situation will result 2O and 2H produces no H2O
while(true) {
CountDownLatch first = hq.take();
CountDownLatch second = hq.poll();
if (second == null) {
hq.add(first);
continue;
}
first.countDown();
second.countDown();
return this;
}
}
}
f********d
发帖数: 51
53
in a concurrent implementation, Thread.sleep is always a big NONO

【在 m*****n 的大作中提到】
: package test;
: import java.util.concurrent.atomic.AtomicInteger;
: import java.util.concurrent.atomic.AtomicLong;
: import test.IElements.WaterElements;
: public class H2OLockFree {
: private final AtomicLong sequencer = new AtomicLong();
: private final AtomicInteger contention = new AtomicInteger();
: public void addO() {
: addElements(WaterElements.O);
: }

f********d
发帖数: 51
54
另外一个思路如果你面试的是hedge fund,会给你大加分
http://en.wikipedia.org/wiki/Reactive_programming
用reactive programing来解决dependency calculation
f********d
发帖数: 51
55
这种题还有比较重要的是unit test,怎么在unit test模拟multi threading 的多种可
能出现的情况。
怎么assert
F****n
发帖数: 3271
56
你的都不对,
LZ的把简单问题复杂化了
要用java.util.concurrent这题其实很简单
一个ReentrantLock 两个Condition就行了

);

【在 f********d 的大作中提到】
: 没有额外thread的版本
: public class H2O {
: private BlockingQueue hq = Queues.newArrayBlockingQueue();
: public H2O H() {
: CountDownLatch latch = new CountDownLatch(1);
: hq.add(latch);
: latch.await();
: return this;
: }
: public H2O O() {

f********d
发帖数: 51
57
I've passed the unit tests pretty well in different scenarios.
of course you can use ReentrantLock and 2 Conditions. And you need one more
thing which is the CyclicBarrier for the H(2)
Problem came when you implement.
When O came, you normally will signal the Condition for O. but what if there
's no H came before or only one came?
Now you need to await on H's condition.
Now you meet a pretty weird situation of signal first or await first.
normally the strategy to solve is using while(true) and keep trying to avoid
deadlocks.
That's fine the code can work. but can you think of any better way of
handling this and how can it be extended in the future?
First thing come into mind is, why I need that while(true)? because I dont
know whether the other side is waiting by Condition interface. What about
introduce one?
alright, now since you need a collection, what about a concurrent one to
help? BlockingQueue came into the door.
Now i still need condition to do await. now you could do lock and new
condition and await. but the question is, is there any class can do this job
much easier?
That's where the CountDownLatch kicks in.
okay, now back to the extensible question? what if you have C2H4O2? then you
code is pretty messy. using the first approach i gave.
in the process method, The runnable is actually describing how H2O or C2H4O2
. and you could make it better as a DSL and encapsulate and abstract to
Element and ElementDefintion.
in that way, you can loop thru all the ElementDefitions(a formula). now the
constructor can take a DSL of ElementDefinition.
Now to this point, it becomes a trival version of Aggregator in Camel or
Spring integration. now what's left over?
of course, Exception handlings.
There will be more considierations on that front, but this is also a test to
see how sophisticated the interviewee is.
btw, I used the same questioin in my interviews. very few people can go this
far.
f********d
发帖数: 51
58
while(true) {
CountDownLatch o = oq.take(); // take an O
CountDownLatch h1 =hq.take(); // take an H
hq.take().countDown(); // take another H
h1.countDown(); // count down all the rest
o.countDown();
}
any new formula, you only need to make sure the first 3 lines reflects your
formula well. it becomes very extensible. and you can also do
Collection list = Lists.newArrayList();
for (ElementDefinition ed : defs) {
BlockingQueue queue = ed.getQueue();
for (int i =0; i < ed.getNumber() ; i++) {
list.add(queue.take());
}
}
for (CountDownLAtch latch : list) {
latch.countDown();
}
with DSL, you could
val H2 = new ElementDefinition(2);
val O = new ElementDefinition(1);
defs.add(H2);
defs.add(O);
void H() {
H2.await();
}
class ElementDefinition {
....
public void await() {
CountDownLatch latch = new CountDownLatch(1);
queue.add(latch);
latch.await();
}
....
}
this is synchronized implementaiton. you can also have interface Element to
replace CountDownLAtch.
for synchronized implementation, use ElementSychImpl with CountDownLatch.
for asycn, get a call back.
Now the codes will be quite extensible and easier to understand

more
there
avoid

【在 f********d 的大作中提到】
: I've passed the unit tests pretty well in different scenarios.
: of course you can use ReentrantLock and 2 Conditions. And you need one more
: thing which is the CyclicBarrier for the H(2)
: Problem came when you implement.
: When O came, you normally will signal the Condition for O. but what if there
: 's no H came before or only one came?
: Now you need to await on H's condition.
: Now you meet a pretty weird situation of signal first or await first.
: normally the strategy to solve is using while(true) and keep trying to avoid
: deadlocks.

i*******6
发帖数: 107
59
My 5 cents:
import java.util.concurrent.*;
class MyO implements Runnable{
int index;
CountDownLatch lock;
public MyO (int index, CountDownLatch lock) {
this.index = index;
this.lock = lock;
}
public void run() {
try {
Thread.sleep((long) (Math.random() * 1000));
lock.await();
System.out.println("Take O:" + index + " to form an H2O!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
class MyH implements Runnable{
int index;
CountDownLatch lock;
public MyH(int index, CountDownLatch lock) {
this.index = index;
this.lock = lock;
}
public void run() {
try {
hread.sleep((long) (Math.random() * 1000));
lock.await();
System.out.println("take H:"+index+" to form a H2O!");
} catch(Exception e) {
e.printStackTrace();
}
}
}
public class MyH2O {
private static BlockingQueue hq = new
LinkedBlockingQueue();
private static BlockingQueue oq = new
LinkedBlockingQueue();
public static void main(String args[]){
ExecutorService service = Executors.newCachedThreadPool();
service.submit(new Thread() {
public void run(){
try{
while (true) {
Thread.sleep((long) (Math.random() * 1000));
CountDownLatch firstH = hq.take();
CountDownLatch secondH = hq.poll();
CountDownLatch firstO = oq.take();
if (secondH == null) {
hq.add(firstH);
continue;
}
firstH.countDown();
secondH.countDown();
firstO.countDown();
System.out.println("A H2O created!");
break;
}
} catch(Exception e) {
e.printStackTrace();
}
}
});
for (int i=0;i<100;i++) {
CountDownLatch lock = new CountDownLatch(1);
int type = (int)(Math.random()*2);
if (type == 0){
hq.add(lock);
service.submit(new MyH(i+1,lock));
} else {
oq.add(lock);
service.submit(new MyO(i+1,lock));
}
}
service.shutdown();
}
}
n********r
发帖数: 102
60
mark一下。。学习了
相关主题
L 家面经面试的时候让你写一个thread pool,能写正确的来举手
面试时候差点想直接推门走,真有这感觉!java concurrence 例子
想问一下那道H2O的多线程题Java concurrency 面试题
进入JobHunting版参与讨论
m*****n
发帖数: 204
61
我对CountDownLatch没太多想过。学习了。

);
);

【在 f********d 的大作中提到】
: 如果允许我大展身手的话。我会用EIP Aggregator pattern
: http://www.eaipatterns.com/Aggregator.html
: 如果要考我java,我就用 new concurrent package, 简单明了
: public class H2O {
: private BlockingQueue hq = Queues.newArrayBlockingQueue();
: private BlockingQueue oq = Queues.newArrayBlockingQueue();
: public H2O H() {
: CountDownLatch latch = new CountDownLatch(1);
: hq.add(latch);
: latch.await();

z*******3
发帖数: 13709
62
原题:
3: 实现两个函数: H() and O(), 这两个函数会被多线程调用。当一个线程调用H或O时
,如果当前已经有至少两个线程call H和一个线程call O。那么让两个call H和一个
call O的线程返回(产生一个水分子),其他的都block。
我随手写了一个,不想用synchronized关键字
这个要搞起来的确比较麻烦,想上java.util.concurrent
研究了一下copyonwritearraylist,还是不行,两个方法都得上synchronized
List l = new ArrayList();
public synchronized void h(){
if(l.size()>=2){
Thread hThread = l.get(0);
Thread oThread = l.get(l.size()-1);
if(hThread.isH() && oThread.isO()){
hThread.notify();
oThread.notify();
return;
}
}
Thread currentThread = Thread.getCurrentThread();
l.add(0,currentThread);
currentThread.wait();
}
public synchronized void o(){
if(l.size()>=2){
Thread hThread1 = l.get(0);
Thread hThread2 = l.get(1);
if(hThread1.isH() && hThread2.isH()){
hThread1.notify();
hThread2.notify();
return;
}
}
Thread currentThread = Thread.getCurrentThread();
l.add(currentThread);
currentThread.wait();
}
z*******3
发帖数: 13709
63
isH()和isO()要扩展一下,要额外加一个类
包装thread对象以及该thread读取的是o还是h
要不然thread本身是没有这个方法的
class ThreadInfo{
private Thread thread;
private boolean isH;
//setter/getter method
...
}
然后把l里面保存的全部换成ThreadInfo对象
z*******3
发帖数: 13709
64
或者找个map寄存
不过增加的map自然增加了查找的时间
效率上不如包装类
List l= new ArrayList();
Map m= new HashMap();
public synchronized void h(){
if(l.size()>=2){
Thread hThread = l.get(0);
Thread oThread = l.get(l.size()-1);
if(m.get(hThread) && !m.get(oThread)){
hThread.notify();
oThread.notify();
return;
}
}
Thread currentThread = Thread.getCurrentThread();
l.add(0,currentThread);
m.put(currentThead, true);
currentThread.wait();
}
public synchronized void o(){
if(l.size()>=2){
Thread hThread1 = l.get(0);
Thread hThread2 = l.get(1);
if(m.get(hThread1) && m.get(hThread2)){
hThread1.notify();
hThread2.notify();
return;
}
}
Thread currentThread = Thread.getCurrentThread();
l.add(currentThread);
m.put(currentThread, false);
currentThread.wait();
}
z*******3
发帖数: 13709
65
汗,实验了一下,有三个小问题,看来多线程白板还是难以bug free,需要多练习
getCurrentThread() -> currentThread()
currentThread.wait() -> wait()
hThread.notify() -> synchronized(hThread){ hThread.notify();}
z*******3
发帖数: 13709
66
List l = new ArrayList();

public synchronized void h() throws InterruptedException {
if (l.size() >= 2) {
ThreadInfo hThread = l.get(0);
ThreadInfo oThread = l.get(l.size() - 1);
if (hThread.isH() && oThread.isO()) {
synchronized(hThread){hThread.notify();}
synchronized(oThread){oThread.notify();}
l.remove(hThread);
l.remove(oThread);
return;
}
}
Thread currentThread = Thread.currentThread();
ThreadInfo ti = new ThreadInfo();
ti.setH(true);
ti.setT(currentThread);
l.add(0, ti);
wait();
}
public synchronized void o() throws InterruptedException {
if (l.size() >= 2) {
ThreadInfo hThread1 = l.get(0);
ThreadInfo hThread2 = l.get(1);
if (hThread1.isH() && hThread2.isH()) {
synchronized(hThread1){hThread1.notify();}
synchronized(hThread2){hThread2.notify();}
l.remove(hThread1);
l.remove(hThread2);
return;
}
}
Thread currentThread = Thread.currentThread();
ThreadInfo ti = new ThreadInfo();
ti.setH(false);
ti.setT(currentThread);
l.add(ti);
wait();
}
F****n
发帖数: 3271
67
不太对,
你的wait没有notify
而且h()和o()都全部synchronized
只用synchronized的解法我前面写过。

【在 z*******3 的大作中提到】
: List l = new ArrayList();
:
: public synchronized void h() throws InterruptedException {
: if (l.size() >= 2) {
: ThreadInfo hThread = l.get(0);
: ThreadInfo oThread = l.get(l.size() - 1);
: if (hThread.isH() && oThread.isO()) {
: synchronized(hThread){hThread.notify();}
: synchronized(oThread){oThread.notify();}
: l.remove(hThread);

z*******3
发帖数: 13709
68
行不行直接开几个thread跑一下不就知道了
notify在中间
一旦执行notify就会return,不再执行wait
一旦执行wait,就压入l等待其他thread notify
并不是所有的thread都需要压入list
只要条件合适,有足够的h和o在list里面,就不需要压入,直接跑完线程
而且计算l.size()的mean应该在4左右
hhhhhhhhhh或者oooooooh的概率极低
大多数时候是hhhh或者oooh甚至更短,hh的来个o就清零了
这种长度还当成大list来做java.util.concurrent就搞笑了

【在 F****n 的大作中提到】
: 不太对,
: 你的wait没有notify
: 而且h()和o()都全部synchronized
: 只用synchronized的解法我前面写过。

F****n
发帖数: 3271
69
你知道你的hThread.notify() notify不到 wait()把???

【在 z*******3 的大作中提到】
: 行不行直接开几个thread跑一下不就知道了
: notify在中间
: 一旦执行notify就会return,不再执行wait
: 一旦执行wait,就压入l等待其他thread notify
: 并不是所有的thread都需要压入list
: 只要条件合适,有足够的h和o在list里面,就不需要压入,直接跑完线程
: 而且计算l.size()的mean应该在4左右
: hhhhhhhhhh或者oooooooh的概率极低
: 大多数时候是hhhh或者oooh甚至更短,hh的来个o就清零了
: 这种长度还当成大list来做java.util.concurrent就搞笑了

z*******3
发帖数: 13709
70
而且我看了下,原来设计,没有循环语句
也就是说,无论l.size怎么变
执行的效率都是一样的,复杂度是O(1)常量
那这个时候做多线程的优化就没有必要了
完全可以把那一小段当成原子操作来执行
反正每次执行就那么点时间,无所谓
另外也没有侵入他人代码,不改写Thread之类的
更没有sleep这种可怕的方法,蛮好
相关主题
Java concurrency 面试题怎么练习multi-threading,平常工作都是用Java框架
一道多线程的面试题Amazon一道synchronization的面试题
LinkedIn 面经问个thread synchronization的问题
进入JobHunting版参与讨论
z*******3
发帖数: 13709
71
我都说了,你自己写个main试试不就知道了?

【在 F****n 的大作中提到】
: 你知道你的hThread.notify() notify不到 wait()把???
F****n
发帖数: 3271
72
你就解释一下为啥hThread.notify()能影响wait()吧

【在 z*******3 的大作中提到】
: 我都说了,你自己写个main试试不就知道了?
z****e
发帖数: 54598
73
因为wait的monitor在l上,而不是在ti上
这个问题可以单独剥离出来看,如果写成一堆的话
那就非常不容易阅读了,这是代码
List l = new ArrayList();

public void h() throws InterruptedException {
ThreadInfo ti =null;

synchronized(l){
if (l.size() >= 2) {
ThreadInfo hThread = l.get(0);
ThreadInfo oThread = l.get(l.size() - 1);
if (hThread.isH() && oThread.isO()) {
synchronized(hThread){
hThread.notified();
hThread.notify();
}
synchronized(oThread){
oThread.notified();
oThread.notify();
}
l.remove(hThread);
l.remove(oThread);
System.out.println("1 h2o");
return;
}
}
Thread currentThread = Thread.currentThread();
ti = new ThreadInfo();
ti.setH(true);
ti.setT(currentThread);
l.add(0, ti);
}
synchronized(ti){
if(ti!=null && !ti.isNotified())
ti.wait();
}
}
public void o() throws InterruptedException {
ThreadInfo ti =null;
synchronized(l){
if (l.size() >= 2) {
ThreadInfo hThread1 = l.get(0);
ThreadInfo hThread2 = l.get(1);
if (hThread1.isH() && hThread2.isH()) {
synchronized(hThread1){
hThread1.notified();
hThread1.notify();
}
synchronized(hThread2){
hThread2.notified();
hThread2.notify();
}
l.remove(hThread1);
l.remove(hThread2);
System.out.println("1 h2o");
return;
}
}
Thread currentThread = Thread.currentThread();
ti = new ThreadInfo();
ti.setH(false);
ti.setT(currentThread);
l.add(ti);
}

synchronized(ti){
if(ti!=null && !ti.isNotified())
ti.wait();
}
}
-----------------------------
测试结果
o
h
o
h
1 h2o
end .......,Thread[Thread-5,5,main]
end .......,Thread[Thread-3,5,main]
end .......,Thread[Thread-4,5,main]
h
h
1 h2o
end .......,Thread[Thread-2,5,main]
end .......,Thread[Thread-6,5,main]
end .......,Thread[Thread-1,5,main]
-------------------------------
class ThreadInfo{
private boolean isNotified=false;
private Thread t;
private boolean isH;
public Thread getT() {
return t;
}
public void setT(Thread t) {
this.t = t;
}
public boolean isH() {
return isH;
}
public void setH(boolean isH) {
this.isH = isH;
}

public boolean isO() {
return !isH();
}

public void notified(){
this.isNotified = true;
}

public boolean isNotified(){
return this.isNotified;
}
}

【在 F****n 的大作中提到】
: 你就解释一下为啥hThread.notify()能影响wait()吧
F****n
发帖数: 3271
74
wait(); 的 monitor 怎么会在 l 上?
wait(); <=> this.wait();

【在 z****e 的大作中提到】
: 因为wait的monitor在l上,而不是在ti上
: 这个问题可以单独剥离出来看,如果写成一堆的话
: 那就非常不容易阅读了,这是代码
: List l = new ArrayList();
:
: public void h() throws InterruptedException {
: ThreadInfo ti =null;
:
: synchronized(l){
: if (l.size() >= 2) {

P****d
发帖数: 137
75
MARK
c*****0
发帖数: 19
76
如果没理解错,直接用两个semaphore不行吗
public void H() {
p1.release(1);
p2.acquire(1);
}
public void O() {
p2.release(2);
p1.acquire(2);
}

AtomicInteger
date

【在 m*****n 的大作中提到】
: 原题见http://www.mitbbs.com/article_t/JobHunting/32331973.html
: 这道题不是单纯作对就好的。那里贴出的解法有些值得商榷的地方。我这里谈谈个人见
: 解供大家参考。
: 从Java的角度看这道题可以有三个考点:
: 对Java Synchronization and Concurrency的掌握
: 基本的Coding Style,要能扩展,不能写spaghetti code
: 有把握的话可以讨论一下Lock Free Synchronization. 这题理论上只用AtomicInteger
: 也行。
: 看到这道题之后首先应该和面试者交流一下,看是否一定要用synchronized-wait-
: notify. 如果不要求就不要用了,用这个既花时间又容易出错,还显得不够up to date

b**m
发帖数: 1466
77
I think mine is short, not tested.
public class PH2O {
private static final Object PLACE_HOLDER = new Object();
AtomicInteger extraH = new AtomicInteger();
BlockingQueue requiredO = new LinkedBlockingDeque();
BlockingQueue releasedH = new LinkedBlockingDeque();
public void h() throws InterruptedException {
while (true) {
if (extraH.compareAndSet(1, 0)) {
requiredO.add(new Object());
break;
}
if (extraH.compareAndSet(0, 1)) {
break;
}
}
releasedH.take();
}
public void o() throws InterruptedException {
requiredO.take();
releasedH.offer(PLACE_HOLDER);
releasedH.offer(PLACE_HOLDER);
}
}
b**m
发帖数: 1466
78
似乎没问题。

【在 c*****0 的大作中提到】
: 如果没理解错,直接用两个semaphore不行吗
: public void H() {
: p1.release(1);
: p2.acquire(1);
: }
: public void O() {
: p2.release(2);
: p1.acquire(2);
: }
:

w*******s
发帖数: 138
79
太复杂了,前面有人说了,一个Lock挂两个ConditionObject就直接搞定了

【在 b**m 的大作中提到】
: I think mine is short, not tested.
: public class PH2O {
: private static final Object PLACE_HOLDER = new Object();
: AtomicInteger extraH = new AtomicInteger();
: BlockingQueue requiredO = new LinkedBlockingDeque();
: BlockingQueue releasedH = new LinkedBlockingDeque();
: public void h() throws InterruptedException {
: while (true) {
: if (extraH.compareAndSet(1, 0)) {
: requiredO.add(new Object());

x*******i
发帖数: 26
80
O() can release 2 permits while there is only one H thread waiting. The H()
then is unblocked. 不符合题目要求把。

【在 c*****0 的大作中提到】
: 如果没理解错,直接用两个semaphore不行吗
: public void H() {
: p1.release(1);
: p2.acquire(1);
: }
: public void O() {
: p2.release(2);
: p1.acquire(2);
: }
:

相关主题
求问一道multithreading问题Linked电面分享,挺好的题 应该已挂
关于死锁疑问请教银行系统设计题,请看我写的code
实现一个 thread-safe blocking queue这题怎么写啊?L家的常考请教L家生成H2O水分子的题。
进入JobHunting版参与讨论
m****h
发帖数: 6
81
mark
p*****3
发帖数: 488
82
是不是可以这么做:
在两个类里分别维护两个static violate counter
H.currentCounter/H.bar
O.currentCounter/O.bar
每次一个H或者O线程创建的时候付一个id = currentCounter++;
每一个线程创建的时候check counter 和 bar看看是不是有满足构成H2O的3个线程存在
,如果自己是其中之一的话忽略(好像题目是这么要求的), 如果有的话提高bar,H.bar
+= 2, O.bar += 1, 这段check和修改的代码要保护, 然后NotifyALL, 然后自己wait

其他线程从wait中醒来后check自己的id和bar, 如果bar > id, return 否则继续wait
1 (共1页)
进入JobHunting版参与讨论
相关主题
L 家面经怎么练习multi-threading,平常工作都是用Java框架
面试时候差点想直接推门走,真有这感觉!Amazon一道synchronization的面试题
想问一下那道H2O的多线程题问个thread synchronization的问题
面试的时候让你写一个thread pool,能写正确的来举手求问一道multithreading问题
java concurrence 例子关于死锁疑问
Java concurrency 面试题实现一个 thread-safe blocking queue这题怎么写啊?L家的常考
一道多线程的面试题Linked电面分享,挺好的题 应该已挂
LinkedIn 面经请教银行系统设计题,请看我写的code
相关话题的讨论汇总
话题: thread话题: public话题: void话题: threadinfo