一起做面试题--Java多线程交替打印

这道面试题的内容是,要求两个线程交替打印,打印出"12A34B56C78D910E1112F1314G1516H1718I1920J2122K2324L2526M2728N2930O3132P3334Q3536R3738S3940T4142U4344V4546W4748X4950Y5152Z"。

一个线程只打印数字,另一个线程只打印字母,打印数字的线程打印两个数字后,打印字母的线程打印一个字母,然后交替下去直到打印完所有字母,数字打印到52即可。

这个的思路就是线程交替运行,交替运行的关键在于,一个线程执行完一个周期,立即挂起,同时通知另一个线程执行,另一个线程执行完,同样立即挂起,再通知之前的线程。两个线程都需要挂起和获得通知,但是两个线程是互相独立的,所以用对象监视器锁是不合适的,因为对象监视器的挂起和通知是无差异的,有可能会在挂起后将本线程立即激活,而需要被激活的线程仍在被挂起。。。所以这里要用ReentrantLock和两个Condition,不多说了看代码。

//线程A负责打印数字

class ThreadA extends Thread{
//一个锁和两个Condition

        private Lock lock;
private Condition c1;
private Condition c2;

//构造方法注入这些引用
public ThreadA(Lock lock,Condition c1,Condition c2){
this.lock=lock;
this.c1=c1;
this.c2=c2;
}
//线程开始
public void run(){
try {
lock.lock();//加锁

                        //循环52次
for(int i=1;i<=52;i++){
//i为奇数时可以打印,打印两次

                                     if(i%2!=0){
System.out.print(i+""+(i+1));
c2.signal();//通知c2这个condition开始运行
}else{
c1.await();//i为偶数时c1挂起
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
}


class ThreadB extends Thread{
private Lock lock;
private Condition c1;
private Condition c2;

public ThreadB(Lock lock,Condition c1,Condition c2){
this.lock=lock;
this.c1=c1;
this.c2=c2;
}

public void run(){
  try {
lock.lock();
  char c='A';//定义char变量作为打印变量
  for(int i=0;i<51;i++){//循环51次,因为遍历26个字母并且每个字母之间插入两个数字的话,需要循环51次,我是调试出来的,最初我也不知道需要51次。。。这里并不把char作为循环变量因为涉及到的是奇数次循环时不打印,所以char如果作为循环变量会跳过奇数次循环,会丢失打印。
  if(i%2==0){//偶数次循环时打印c并自增,通知c1这个condition可以运行。
  System.out.print(c++);
  c1.signal();
  }else{//循环奇数次时,c2这个condition挂起。
  c2.await();
  }
  }
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
}


这是两个线程类,看main方法。

public static void main(String[] args) throws InterruptedException {
Lock lock=new ReentrantLock();
Condition c1=lock.newCondition();
Condition c2=lock.newCondition();
ThreadA a=new ThreadA(lock,c1,c2);
ThreadB b=new ThreadB(lock,c1,c2);
a.start();
Thread.sleep(50);
b.start();
}

这个没什么难的,线程A先启动,然后线程B再启动。结果正确。

我写的不一定是最好的,肯定有更优的解法,欢迎大家指正。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java面试题真的很多,下面我来回答一个有关多线程的问题。 在Java中实现多线程有两种方式,一种是继承Thread类,另一种是实现Runnable接口。这两种方式有何区别? 继承Thread类的方式是直接定义一个类继承Thread,并重写它的run()方法。然后创建该类的对象,并调用对象的start()方法来启动线程。这种方式简单直接,但因为Java是单继承的,所以如果某个类已经继承了其他类,就不能再直接继承Thread类实现多线程。 实现Runnable接口的方式是定义一个类实现Runnable接口,并实现其唯一的抽象方法run()。然后创建Thread类的对象,将实现了Runnable的对象作为参数传递给Thread类的构造方法。最后调用Thread对象的start()方法来启动线程。这种方式灵活性更大,因为Java允许一个类实现多个接口,所以即使某个类已经继承了其他类,仍然可以通过实现Runnable接口来实现多线程。 另一个区别在于资源共享的问题。继承Thread类的方式,不管是数据还是方法,都是线程自己拥有的,不存在共享的情况。而实现Runnable接口的方式,多个线程可以共享同一个对象的数据和方法,因为多个线程共同操作的是同一个Runnable对象。 总结来说,继承Thread类方式简单直接,但只能通过单继承来实现多线程;实现Runnable接口方式更灵活,可以解决单继承的限制,并且多个线程可以共享同一个Runnable对象的数据和方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值