问题是:启动3个线程顺序打印ABC 10次,不能使用sleep。
方案一:
public class ThreadDemo{
public static void main(String[] args) {
MyLock lock = new MyLock();
Thread a = new Thread(new MyPrinter("A", "B", lock));
Thread b = new Thread(new MyPrinter("B", "C", lock));
Thread c = new Thread(new MyPrinter("C", "A", lock));
a.start();
b.start();
c.start();
lock.setHolder("A");
}
static class MyPrinter implements Runnable {
private String myName;
private String nextName;
private final MyLock lock;
public MyPrinter(String myName, String nextName, MyLock lock) {
this.myName = myName;
this.nextName = nextName;
this.lock = lock;
}
public void run() {
int count = 3;
while (count > 0) {
if (lock != null && lock.getHolder() != null && lock.getHolder().equals(myName)) {
synchronized (lock) {
System.out.print(myName);
count--;
lock.setHolder(nextName);
}
}
}
}
}
static class MyLock {
public MyLock() {
}
private String holder;
public String getHolder() {
return holder;
}
public void setHolder(String holder) {
this.holder = holder;
}
}
}
方案二:
对上一个方案进行修改:把count定义为static,不然每个线程之间可没法共享count变量,且由于是输出后再--,故设置成9比较合适。
public class ThreadDemo{
public static void main(String[] args) {
MyLock lock = new MyLock();
Thread a = new Thread(new MyPrinter("A", "B", lock));
Thread b = new Thread(new MyPrinter("B", "C", lock));
Thread c = new Thread(new MyPrinter("C", "A", lock));
a.start();
b.start();
c.start();
lock.setHolder("A");
}
static class MyPrinter implements Runnable {
private String myName;
private String nextName;
private final MyLock lock;
static int count = 9;
public MyPrinter(String myName, String nextName, MyLock lock) {
this.myName = myName;
this.nextName = nextName;
this.lock = lock;
}
public void run() {
while (count > 0) {
if (lock != null && lock.getHolder() != null && lock.getHolder().equals(myName)) {
synchronized (lock) {
System.out.print(myName);
count--;
lock.setHolder(nextName);
}
}
}
}
}
static class MyLock {
public MyLock() {
}
private String holder;
public String getHolder() {
return holder;
}
public void setHolder(String holder) {
this.holder = holder;
}
}
}
方案三:
本质应该是操作系统中的同步问题,设定好信号量,使用PV元语就可以。要用java实现的话,使用wait()和notify()应该就OK。
public class ThreadDemo {
public static void main(String[] args) {
final int count = 3;
String[] abc = { "a", "b", "c" };
for (int i = 0; i < abc.length; i++) {
final String current = abc[i];
final String next = abc[(i + 1) % abc.length];
new Thread(new Runnable() {
public void run() {
for (int j = 0; j < count; j++) {
synchronized (current) {
// 等待信号
try {
current.wait();
} catch (InterruptedException e) {
}
System.out.print(current);
// 给下个线程发信号
synchronized (next) {
next.notify();
}
}
}
}
}).start();
}
// 通给第一个线程发信号
synchronized (abc[0]) {
abc[0].notify();
}
}
}
可用用如下方式分析(参考)
public class ThreadDemo {
public static void main(String[] args) {
final int count = 3;
String[] abc = { "a", "b", "c" };
for (int i = 0; i < abc.length; i++) {
final String current = abc[i];
final String next = abc[(i + 1) % abc.length];
new Thread(new Runnable() {
public void run() {
for (int j = 0; j < count; j++) {
synchronized (current) {
// 等待信号
System.out.println(current + "等待信号");
try {
current.wait();
} catch (InterruptedException e) {
}
System.out.println(current + "给下一个线程发信号");
// 给下个线程发信号
synchronized (next) {
next.notify();
}
}
System.out.println("第" + j + "次循环");
}
}
}).start();
}
// 通给第一个线程发信号
System.out.println("给第一个线程发信号");
synchronized (abc[0]) {
abc[0].notify();
}
}
}
方案四:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadDemo {
private static Lock lock = new ReentrantLock();//通过JDK5中的锁来保证线程的访问的互斥
private static int state = 0;
static class ThreadA extends Thread {
@Override
public void run() {
for (int i = 0; i < 3;) {
lock.lock();
if (state % 3 == 0) {
System.out.print("A");
state++;
i++;
}
lock.unlock();
}
}
}
static class ThreadB extends Thread {
@Override
public void run() {
for (int i = 0; i < 3;) {
lock.lock();
if (state % 3 == 1) {
System.out.print("B");
state++;
i++;
}
lock.unlock();
}
}
}
static class ThreadC extends Thread {
@Override
public void run() {
for (int i = 0; i < 3;) {
lock.lock();
if (state % 3 == 2) {
System.out.print("C");
state++;
i++;
}
lock.unlock();
}
}
}
public static void main(String[] args) {
new ThreadA().start();
new ThreadB().start();
new ThreadC().start();
}
}
方案五:
使用lock来保证只有一个线程在输出操作, 要保证了state不会被两个线程同时修改, 还可以使用condition, condition的效率可能会更高一些, await会释放lock锁, condition的await和signal与object的wait和notify方法作用类似
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadDemo {
private static Lock lock = new ReentrantLock();
private static int count = 0;
private static Condition A = lock.newCondition();
private static Condition B = lock.newCondition();
private static Condition C = lock.newCondition();
static class ThreadA extends Thread {
@Override
public void run() {
lock.lock();
try {
for (int i = 0; i < 3; i++) {
while (count % 3 != 0)
A.await(); // 会释放lock锁
System.out.print("A");
count++;
B.signal(); // 唤醒相应线程
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
static class ThreadB extends Thread {
@Override
public void run() {
lock.lock();
try {
for (int i = 0; i < 10; i++) {
while (count % 3 != 1)
B.await();
System.out.print("B");
count++;
C.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
static class ThreadC extends Thread {
@Override
public void run() {
lock.lock();
try {
for (int i = 0; i < 10; i++) {
while (count % 3 != 2)
C.await();
System.out.print("C");
count++;
A.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
new ThreadA().start();
new ThreadB().start();
ThreadC threadC = new ThreadC();
threadC.start();
threadC.join();
System.out.println(count);
}
}