这是我在学校经常听到的一个问题,但是直到被要求面试之前,从来没有理由惹麻烦。
提示::使用2个线程依次打印"Thread i: The number is 'j'"
,其中j = 1:100,而i是线程号。线程1只能打印奇数j,线程2只能打印偶数j。
编辑,必须对j的输出进行排序
这是我的尝试,但我没有继续进行采访。我缺少任何基本的部分吗?有什么优化吗?
import java.util.concurrent.Semaphore;
public class ThreadSynchronization implements Runnable {
private int start;
private Semaphore semaphore;
private ThreadSynchronization(int start, Semaphore semaphore) {
this.start = start;
this.semaphore = semaphore;
}
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(1, true);
semaphore.acquireUninterruptibly();
start(1, semaphore);
start(2, semaphore);
semaphore.release();
}
private static void start(int start, Semaphore semaphore) {
ThreadSynchronization ts = new ThreadSynchronization(start, semaphore);
Thread thread = new Thread(ts);
thread.start();
while (thread.getState() != Thread.State.WAITING) ;
}
@Override
public void run() {
for (int i = start; i <= 100; i += 2) {
semaphore.acquireUninterruptibly();
System.out.println("Thread " + start + ": The number is '" + i + "'");
semaphore.release();
}
}
}
答案 0 :(得分:1)
一个线程可以继续获取并释放Semaphore
,而另一个线程则处于饥饿状态。
您可以使用wait
和notify
进行此操作,请尝试以下操作:
import java.util.concurrent.atomic.AtomicInteger;
class Odd implements Runnable {
private AtomicInteger integer;
private final Object lock;
public Odd(AtomicInteger integer, Object lock) {
this.integer = integer;
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
try {
while (integer.get() <= 100) {
while (integer.get() % 2 == 0) {
lock.notify();
lock.wait();
}
if (integer.get() <= 100) {
System.out.println("Thread " +
Thread.currentThread().getName() + ": The number is '" + integer.get() + "'");
}
integer.getAndIncrement();
lock.notify();
}
} catch (Exception e) {
}
}
}
}
class Even implements Runnable {
private AtomicInteger integer;
private final Object lock;
public Even(AtomicInteger integer, Object lock) {
this.integer = integer;
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
try {
while (integer.get() <= 100) {
while (integer.get() % 2 != 0) {
lock.notify();
lock.wait();
}
if (integer.get() <= 100) {
System.out.println("Thread " +
Thread.currentThread().getName() + ": The number is '" + integer.get() + "'");
}
integer.getAndIncrement();
lock.notify();
}
} catch (Exception e) {
}
}
}
}
public class ThreadSynchronization {
public static void main(String[] args) throws Exception{
Object lock = new Object();
AtomicInteger integer = new AtomicInteger(1);
Odd odd = new Odd(integer, lock);
Even even = new Even(integer, lock);
Thread thread1 = new Thread(odd, "1");
Thread thread2 = new Thread(even, "2");
thread1.start();
thread2.start();
thread1.join();
thread2.join();
}
}
答案 1 :(得分:1)
使用对象进行仲裁:
public class Switch {
private boolean expected;
public Switch(boolean init) {
expected = init;
}
public void waitFor(boolean value) {
synchronized(this) {
while (value != expected) {
try {
wait();
} catch (InterruptedException ex) {
// deal with it
}
}
expected = !expected;
notifyAll();
}
}
}
然后:
public class ThreadSynchronization implements Runnable {
private static Switch arbiter = new Switch(true);
private int start;
private ThreadSynchronization(int start) {
this.start = start;
}
public static void main(String[] args) {
start(1);
start(2);
}
private static void start(int start) {
ThreadSynchronization ts = new ThreadSynchronization(start);
Thread thread = new Thread(ts);
thread.start();
}
@Override
public void run() {
boolean odd = start%2 != 0;
for (int i = start; i <= 100; i += 2) {
arbiter.waitFor(odd);
System.out.println("Thread " + start + ": The number is '" + i + "'");
}
}
}
答案 2 :(得分:1)
您非常接近正确的解决方案,但是该任务需要2个信号灯:
public class ThreadSynchronization implements Runnable {
private int start;
private Semaphore semaphore1;
private Semaphore semaphore2;
private ThreadSynchronization(int start, Semaphore semaphore1, Semaphore semaphore2) {
this.start = start;
this.semaphore1 = semaphore1;
this.semaphore2 = semaphore2;
}
private static void start(int start, Semaphore semaphore1, Semaphore semaphore2) {
ThreadSynchronization ts = new ThreadSynchronization(start, semaphore1, semaphore2);
Thread thread = new Thread(ts);
thread.start();
}
@Override
public void run() {
for (int i = start; i <= 100; i += 2) {
semaphore1.acquireUninterruptibly();
System.out.println("Thread " + start + ": The number is '" + i + "'");
semaphore2.release();
}
}
public static void main(String[] args) {
Semaphore semaphore1 = new Semaphore(1);
Semaphore semaphore2 = new Semaphore(0);
start(1, semaphore1, semaphore2);
start(2, semaphore2, semaphore1); // in reverse order
}
}
答案 3 :(得分:0)
对于这个简单的任务,只需使用AutomicInteger
:
public static class CounterTask implements Runnable {
private final int id;
private final AtomicInteger counter;
private final int max;
private final IntPredicate predicate;
public CounterTask(int id, AtomicInteger counter, int max, IntPredicate predicate) {
this.id = id;
this.counter = counter;
this.max = max;
this.predicate = predicate;
}
@Override
public void run() {
while (counter.get() <= max) {
if (predicate.test(counter.get())) {
System.out.format("Thread %d: The number is '%d'\n", id, counter.get());
counter.incrementAndGet();
}
}
}
}
public static void main(String... args) throws InterruptedException {
final int max = 100;
final AtomicInteger counter = new AtomicInteger();
Thread oddThread = new Thread(new CounterTask(1, counter, max, val -> val % 2 == 0));
Thread evenThread = new Thread(new CounterTask(2, counter, max, val -> val % 2 != 0));
oddThread.start();
evenThread.start();
oddThread.join();
evenThread.join();
}
答案 4 :(得分:0)
虽然wait
和notify
可以胜任,但我认为Semaphore
的使用可以使代码更具可读性。下面的代码着重于线程之间相互“交谈”并在需要时进行同步的解决方案:我想象在一个实际用例中,两个线程会做重要的工作,并且在某些时候需要同步并确定谁先行。
import java.util.concurrent.Semaphore;
public class LockStep {
public static void main(String[] args) {
Semaphore evenTurn = new Semaphore(1);
Semaphore oddTurn = new Semaphore(0);
int max = 50;
Thread even = new Thread(new Worker(evenTurn, oddTurn, max));
even.start();
Thread odd = new Thread(new Worker(oddTurn, evenTurn, max));
odd.start();
try {
even.join();
odd.join();
} catch (Exception e) {
System.out.println("No join for me: " + e);
}
System.out.println("Finished");
}
static class Worker implements Runnable {
final Semaphore myTurn;
final Semaphore theirTurn;
final int maxTurns;
public Worker(Semaphore myTurn, Semaphore theirTurn, int maxTurns) {
this.myTurn = myTurn;
this.theirTurn = theirTurn;
this.maxTurns = maxTurns;
}
@Override
public void run() {
int turn = 0;
while (turn < maxTurns) {
try {
myTurn.acquire();
turn += 1;
System.out.println(Thread.currentThread().getName() + " " + turn);
theirTurn.release();
} catch (Exception e) {
System.out.println("Oops: " + e);
}
}
}
}
}