建立三个线程A、B、C, A线程打印10次字母A, B线程打印10次字母B, C线程打印10次字母C,但是要求三个线程同时运行, 并且实现交替打印,即按照ABCABCABC的顺序打印
方法1 wait notify 三个线程执行的顺序是:A打印前一定要是null("")或者C, B打印前一定要是A, C打印前一定要是A。
如何做到呢?让三个线程竞争同一个锁,获取到锁的那个线程才有机会执行打印动作,在执行打印动作之前需要根据规则判断能不能打印,能则打印,不能则释放锁,通知其他线程竞争。
代码如下
/**
* @description:
* @author: lkb
* @create: 2021/9/5
*/
public class ThreadTest {
private volatile String flag = "C";
private synchronized void setFlag(String flag){
this.flag = flag;
System.out.println(Thread.currentThread().getName()+" print " + flag);
}
private String getFlag(){
return this.flag;
}
class PrintThread extends Thread{
private String oldFlag;
private String newFlag;
private Object lock;
public PrintThread(String threadName, String oldFlag, String newFlag, Object lock){
this.oldFlag = oldFlag;
this.newFlag = newFlag;
this.lock = lock;
this.setName(threadName);
}
@Override
public void run() {
synchronized (lock){
for(int i=0;i<10;){
if(StringUtils.equals(getFlag(), oldFlag)){
setFlag(newFlag);
i++;
lock.notifyAll();
}else{
try {
lock.wait();
}catch (InterruptedException e){
System.out.println(e);
}
}
}
}
}
}
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
PrintThread printThreadA = threadTest.new PrintThread("ThreadA", "C","A", threadTest.flag);
PrintThread printThreadB = threadTest.new PrintThread("ThreadB", "A","B", threadTest.flag);
PrintThread printThreadC = threadTest.new PrintThread("ThreadC", "B","C", threadTest.flag);
printThreadA.start();
printThreadB.start();
printThreadC.start();
}
}
方法二 LockSupport.park() / LockSupport.unpark()
这个是抄的网上的。原理就是 LockSupport.unpark(Thread) 可以指定唤醒某个线程,park的作用有点类似wait。
/**
* @description:
* @author: lkb
* @create: 2021/9/5
*/
public class ThreadTest {
static Thread A, B,C;
public static void main(String[] args) {
A = new Thread(()->{
for(int i = 0; i < 10; i++){
LockSupport.park();
System.out.println("A");
LockSupport.unpark(B);
}
});
B = new Thread(()->{
for(int i = 0; i < 10; i++){
LockSupport.park();
System.out.println("B");
LockSupport.unpark(C);
}
});
C = new Thread(()->{
for(int i = 0; i < 10; i++){
LockSupport.unpark(A);
LockSupport.park();
System.out.println("C");
}
});
A.start();
B.start();
C.start();
}
方法三 ReentrantLock 和 Condition
原理和 wait notify 差不多
/**
* @description:
* @author: lkb
* @create: 2021/9/5
*/
public class ThreadTest {
private String stateFlag = "C";
class PrintThread extends Thread{
private Lock lock;
private Condition condition;
private String pre;
private String curr;
public PrintThread(Lock lock, Condition condition, String pre, String curr){
this.lock = lock;
this.condition = condition;
this.pre = pre;
this.curr = curr;
}
@Override
public void run(){
try {
lock.lock();
for(int i=0;i<10;i++){
while(!stateFlag.equals(pre)){
condition.await();
}
stateFlag = curr;
System.out.println(stateFlag);
condition.signalAll();
}
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
PrintThread printThreadA = threadTest.new PrintThread(lock, condition, "C", "A");
PrintThread printThreadB = threadTest.new PrintThread(lock, condition, "A", "B");
PrintThread printThreadC = threadTest.new PrintThread(lock, condition, "B", "C");
printThreadA.start();
printThreadB.start();
printThreadC.start();
}
}
做饭,做一个汤要十分钟,做一个炒菜要十五分钟,要求两个线程分别做汤、做菜,每隔5分钟,每个线程汇报一下结果
这个用Callable去做。
/**
* 做饭,做一个汤要十分钟,做一个炒菜要十五分钟
* 要求两个线程分别做汤、做菜,每隔5分钟,每个线程汇报一下结果
* @author: lkb
* @create: 2021/9/5
*/
public class ThreadTest {
class DoSoup implements Callable{
@Override
public Object call() throws Exception {
Thread.sleep(10*1000);
System.out.println("汤做好了");
return "汤做好了";
}
}
class DoCook implements Callable{
@Override
public Object call() throws Exception {
Thread.sleep(15*1000);
System.out.println("菜做好了");
return "菜做好了";
}
}
public static void main(String[] args) throws Exception{
ThreadTest threadTest = new ThreadTest();
FutureTask doSoupTask = new FutureTask(threadTest.new DoSoup());
Thread threadSoup = new Thread(doSoupTask);
FutureTask doCookTask = new FutureTask(threadTest.new DoCook());
Thread threadCook = new Thread(doCookTask);
threadSoup.start();
threadCook.start();
boolean allFinish = false;
while (!allFinish){
if(doCookTask.isDone() && doSoupTask.isDone()){
break;
}
Thread.sleep(5*1000);
if(!doCookTask.isDone()){
System.out.println("做菜中...");
}
if(!doSoupTask.isDone()){
System.out.println("做汤中...");
}
}
}
}
十个运动员参加跑步比赛,信息部需要在赛后统计十个人的平均耗时
public class ThreadTest {
public static void main(String[] args) throws Exception {
CountDownLatch countDownLatch = new CountDownLatch(10);
AtomicLong total = new AtomicLong(0);
for(int i=0;i<10;i++){
FutureTask<Long> runTask = new FutureTask<>(() -> {
long time = RandomUtil.randomInt(20, 30) * 100L;
Thread.sleep(time);
System.out.println(Thread.currentThread().getName() + " run " +time);
total.getAndAdd(time);
countDownLatch.countDown();
return time;
});
Thread runner = new Thread(runTask);
runner.start();
}
countDownLatch.await();
System.out.println("平均耗时 :" + total.get() / 10);
}