我看到论坛上有个帖子,是介绍某次迅雷面试题目的,其中有一个题目是关于线程的,具体如下:
有三个线程,线程名称分别是A,B,C,要求编写代码实现输出这三个线程的名字  ABCABCABC……一共十次,当然,这三个线程要run起来,也就是说,要在程序中控制三个线程的顺序运行。小弟不才,写了如下一个代码:
package thread;public class threadrecyle {
public static void main(String[] args) {
mythread A = new mythread("A");
mythread B = new mythread("B");
mythread C = new mythread("C");
A.start();B.start();C.start();
}
}
class  mythread extends Thread{
mythread(String s){
this.setName(s);
}
static int j = 0;
static boolean goa = true;
static boolean gob = false;
static boolean goc  = false;
static boolean  = true;
public void run(){
while(  ){
if(this.getName().equals("A") && goa ){
System.out.print(this.getName());
gob = true;
goa = false;
}
 if(this.getName().equals("B") && gob){
System.out.print(this.getName());
goc = true;
gob = false;
}
if(this.getName().equals("C") && goc ){
System.out.print(this.getName());
goa = true;
goc = false;
j++;
if(j==10){goa = false; = false;}
}

}
}
}
虽然可以实现,但是后来在网上逛的时候,发现这样一个问题,线程的目的不就是为了实现并发性么?实现了这个要求,那么跟并发不就违背了么?并发?顺序控制?这看上去时矛盾的啊!或者是我对线程理解的太肤浅么?望各位大侠给出宝贵观点和经验!!

解决方案 »

  1.   

    多线程技术,应该解决的是CPU密集型的问题。
    但是,考题并非全是要解决实际问题的。
    楼主的这道题,其实是想调查程序员,是否有实现线程间相互协作的能力。引入了多线程技术,虽然一定程度上解决了CPU密集型的任务,
    但是,也引入了线程安全、线程协作等一些问题,
    实际应用中,我们可能只专注于某个问题的技术实现方案。
    但,考题,则会侧重某个点来考察你,而非解决实际问题。
      

  2.   

    还有,楼主可以这样想象这个ABC问题。
    可以把一个文件的下载过程,分为三个部分:
    网络数据传输,内存缓冲区数据管理,本地硬盘数据管理。
    那么,其中内存数据管理,很可能就是一个CPU密集型的案例
    (多个数据源公用一个数据缓冲区,并且数据并非都是连贯的,
    这就要求缓冲区管理程序要不停的根据数据源的数据变动,
    以及硬盘数据的写入变动,来调整、管理缓冲区,提高整体效率)当然,我这只是一个假设,如果假设成立,那么,
    整个下载程序,
    网络数据传输部分,只要一个线程来维护多个连接就OK了
    (因为这个工作相对不消耗CPU而多消耗网络通信);
    本地硬盘数据管理部分,只要一两个线程负责多个文件的写入工作就OK了
    (这个工作也是大部分都是硬盘的IO操作,相对不消耗CPU);
    内存数据缓冲区管理部分,相对上述两个部分,以及整体来讲,CPU的消耗要大得多,
    可以考虑多个线程来完成
    (两边的情况都在变动,中间的缓冲区也在变动,所以,需要CPU根据不同的情况,
    及时调整、管理这些数据,使得整体效率提高)。
      

  3.   

    很简单,使用条件锁 ,a锁条件是c执行过了,b锁条件是a执行过了,c锁得条件是b执行过了,初始锁状态是c执行过了,有点晚,明天有空写个例子给你。
      

  4.   

    矛盾吗 线程间高密度地切换,宏观上表现就是并发处理,但对于单cpu本质还是顺序执行
      

  5.   

    我感觉这个顺序打印ABC的题目不是要说明多线程的在速度方面有多大的好处,而是考验一下你对于线程间协作的理解
      

  6.   

    示例:public class ConditionTest {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();
    /** int state:0:c运行完,1:A运行完,2:B运行完 */
    private static int state = 0; public final static int A = 0;
    public final static int B = 1;
    public final static int C = 2;
    /**
     * @Description:
     * @param args
     * @Others:
     */
    public static void main(String[] args) { Mythread threadA = new Mythread(A);
    Mythread threadB = new Mythread(B);
    Mythread threadC = new Mythread(C);
    threadA.start();
    threadB.start();
    threadC.start();
    } public static class Mythread extends Thread {
    private int name;
    Mythread(int name) {
    this.name = name;
    }
    @Override
    public void run() {
    for (int i = 0; i < 10; i++) {
    lock.lock();
    try {
    while (name != state) {
    condition.await();
    }
    switch (name) {
    case A: {
    System.out.print("A");
    break;
    }
    case B: {
    System.out.print("B");
    break;
    }
    case C: {
    System.out.print("C");
    break;
    }
    }
    // 条件满足,执行
    state = (state+1)%3;
    condition.signalAll();
    } catch (InterruptedException e) {
    e.printStackTrace();
    } finally {
    lock.unlock();
    }
    }
    }
    }}
      

  7.   


    boolean a=true,b=false,c=false;
    public void run(){
    while(!Thiread.interrupted()){
    if(a){
    a=false;
    b=true;
    //do a
    }
    if(b){
    b=false;
    c=true;
    //do b
    }
    if(c){
    v=false;
    a=true;
    //do c
    }
    }
    }这个应该也行吧
      

  8.   

    刚开始,可能ABC都执行
    if(a){
    a=false;
    b=true;
    //do a
    }
    打印的是AAA
      

  9.   

    线程除了并发,还有相互协作。所以本题应该是考相互协作。(其实并发只是表象,实际上CPU还是随机按顺序执行多线程的,所以协作很关键)
    顺便说一声,LZ的代码有问题,LZ再好好想想。
      

  10.   

    这个代码什么时候可以停止输出?是不是应该加一个跳出while循环的标识?还是 !Thread.interrupted.()有其他的功能?
      

  11.   

    if(this.getName().equals("A") && goa ){
    System.out.print(this.getName());
    gob = true;
    try {sleep(10);} catch (Exception e) {} //LZ可试着用sleep来模拟CPU分配时间,看看是什么结果
    goa = false;
    }LZ的程序严格依赖各个标志,一旦标志变换顺序被打乱,程序就崩了
    线程的执行是由系统随机调度的,也就是当线程A执行完gob=true时,很有可能CPU被系统收回,此时B执行,C执行,当C执行到goa=true时,假设系统把C的CPU收回,分配给A,而A得到CPU权限后继续下一条代码goa=false;此时标志位乱了,程序无法继续正常执行。
    LZ对线程不熟悉,想的不周到,这不怪你,LZ慢慢体会吧,这只是举例一种可能,因为线程是随机的,所有还有很多可能
      

  12.   

    写的比较繁琐... 发上来求指教一下,求优化一下,
    public class test {
    public static void main(String[] args) {
    pr p = new pr();
    Thread a = new Thread(p);
    a.setName("A");
    a.start();
    Thread b = new Thread(p);
    b.setName("B");
    b.start();
    Thread c = new Thread(p);
    c.setName("C");
    c.start();
    }
    }
    class pr implements Runnable {
    private static int num = 0;
    private static boolean a=true;
    private static boolean b=false;
    private static boolean c=false;
    public synchronized void run() {
    long start = System.currentTimeMillis();
    while(true) {
    if(Thread.currentThread().getName().equals("A")) {
    if(a) {
    System.out.print(Thread.currentThread().getName());
    a=false;
    b=true;
    num++;
    }
    else {
    try {
    this.notifyAll();
    this.wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    if(Thread.currentThread().getName().equals("B")) {
    if(b) {
    b=false;
    c=true;
    System.out.print(Thread.currentThread().getName());
    num++;
    }
    else {
    try {
    this.notifyAll();
    this.wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    if(Thread.currentThread().getName().equals("C")) {
    if(c) {
    c=false;
    a=true;
    System.out.print(Thread.currentThread().getName());
    num++;
    }
    else {
    try {
    this.notifyAll();
    this.wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    if(num==3000) {
    System.out.println();
    System.out.print(System.currentTimeMillis()-start);
    System.exit(0);
    }
    }
    }
    }
    csdn第一帖... 嘿嘿,试试能不能正常发代码
      

  13.   

    楼主的代码我认真看了一下,应该也是能够得到正确的结果,但是楼主的代码存在一个问题因为你的三个线程是无等待循环,若你无限执行,你的线程占用cup应该是100%,这个在实际应用中是行不通的。另外20说的也是在理,楼主的方法,使用单线程,也是可以替代的。
      

  14.   

    21楼也能够得出正确的结果,也使用了同步锁,但是有个两不好的地方1:同步是瓶颈资源,所以你应该尽早释放锁,使其它线程有机会获取同步资源,你不应该在第二次进入循环后再else {try { this.notifyAll();
    2: this.notifyAll();  this.wait();这种写法虽然我推敲了一下没有什么问题,但总觉得怪怪的,我工作几年来好像没有见过这种写法,呵呵。不过总的来说还是挺好的。
      

  15.   

    其实可以sleep一下线程同步下控制下快慢
      

  16.   

    关键的还是一个cpu所以一个时间点只能执行一个线程,这是多线程并不是多核
      

  17.   


    我纯粹是新手,刚看视频自学的。不过阿宝可能说的是同步问题里的东西吧,比如
    gob = true;
    goa = false
    这两句应该加个synchronized.....
    线程是间歇性工作的
    不知道说的对不
      

  18.   

    有话就说清楚,哪里有什么问题,“如果你觉得LZ的代码没问题,那说明你对线程的了解还是太浅了,好好体会我说的吧”,我说过楼主的代码没有问题么,我是说“楼主的代码我认真看了一下,应该也是能够得到正确的结果”,这句话没有错吧,最不喜欢这种指东道西又不说出个所以然的,别人会以为你在装B的,有更好的方案写出来给大家看就行了。
      

  19.   

    哎线程 在不同的业务类型里面是 很复杂的。 。我想一个很有经验的JAVA程序员。
       也不应该说 自己对线程特别拿手的吧。
        大家只是讨论学习。。  在说了 说的对只是针对 楼主这一种类型的。。
      学习才是主要的。
      

  20.   

    我话已经说清楚了,你自己没看清楚
    //LZ可试着用sleep来模拟CPU分配时间,看看是什么结果
    线程的控制是随机的,不是因为你一时的结果正确就表示正确
    你自己说的话有没有错,你自己再好好思考吧。
    年轻人不要浮躁,我在15L的回复如果不是你没好好看,就是你还没完全理解。
    15L已经把Lz的程序漏洞分析清楚了。
    能一眼就看出了Lz的程序有问题,这不是装能装出来的,有本事你也装一个试试。
    不要被人指出错误就进行人身攻击,不懂就要谦虚地去学。
      

  21.   

    32楼的担心不是没有道理的,
    [threadA]
    gob = true;
    [threadB]
    goc = true;
    gob = false;
    [threadB]
    goa = true;
    goc = false;
    [threadA]
    goa = false;
    这种情况下会出现三个变量全为false,导致三个线程全不能进入条件。这种情况打印顺序不会发生变化,但是后面不再会打印了。
      

  22.   

    你自己说的话有没有错,你自己再好好思考吧。
    --说哪里错了就Ok,不要装深沉。
    年轻人不要浮躁,我在15L的回复如果不是你没好好看,就是你还没完全理解。
    15L已经把Lz的程序漏洞分析清楚了。
    能一眼就看出了Lz的程序有问题,这不是装能装出来的,有本事你也装一个试试。
    --我没你会装,不过我在#12楼已经给出了正确的代码。
      

  23.   

    算了,懒得跟你争论,如果这句话换成我说,我会说LZ的代码不一定能运行正确,你自己比较一下谁的说法比较合理吧。
    12L的代码没看,你不装,是因为你根本没看出LZ的问题,你写出代码,无非是想炫耀一下,好让别人评论一番,结果被人忽略后心有不甘。
    你想要代码,我给你一段,最原始的线程协作
    class Job {
        int count = 0;
        
        public static void main(String[] args) {
            new Job().start();
        }
            
        public void start() {
            new JobThread("A", 0).start();
            new JobThread("B", 1).start();
            new JobThread("C", 2).start();
        }
        
        synchronized void doJob(int id) {
            if (count%3 == id) {
                System.out.print(Thread.currentThread().getName());
                count++;
                notifyAll();
            } else {
                try {
                    wait();
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
        }
        
        private class JobThread extends Thread {
            int id;
            
            public JobThread(String name, int id) {
                super(name);
                this.id = id;
            }
            
            public void run() {
                while (Job.this.count < 30) {
                    Job.this.doJob(id);
                    yield();
                }
            }
        }
    }
      

  24.   

    看问题角度不一样而已,我关注的是楼主写的代码有严重的性能问题,“如果这句话换成我说,我会说LZ的代码不一定能运行正确”,这个你说的也在理,但是我们发帖谁会很慎重的检查自己的语言是不是无懈可击,那样就能说明我很肤浅,对线程不了解,你说的
    gob = true;
    goa = false
    这个两个要当做一个原子操作才能保持条件的一致性我又不是不知道,我知道这样会存在问题,但没有仔细去推敲会引起什么问题,所以也就没有在这个问题上下论断,只是说楼主代码能得到正确结果,你说我说的存在什么问题?(不是问你楼主的代码存在什么问题,我从没有说过楼主的代码不存在问题)
      

  25.   

    我挑出LZ的问题,也给LZ具体分析
    你如果真对线程了解,又岂会看不出问题?连LS的年轻人,指点后都能看出来了。
    你的话本来就不严谨,再见上自己又说认真看了一下,于是下了个结论,应该也是能够得到正确的结果,而且,你还是对我的回帖做的回复,也就是说我在帖子里的都把问题说出来了,你还没看出来,还得出这样的结论,说到这里就不用解释了,你懂的,如此认真还找不出问题?不要以为自己写了个程序就表示自己很牛,不知就是不知。你这属于典型的钻牛角尖,明白的人都知道你的解释很苍白,没看出问题来就是没看出问题来,不用作无谓的解释,你自己也说没仔细推敲会引起问题,既知有问题,又岂能草率下结论?而且对你所谓的能得到正确的结果,我也说过一时的结果正确不代表正确,如果非要说别人挑刺,那我就挑出你的语句问题,应该有时能得到正确的结果,这句话和你那句话,意思可谓差远了。有错不可怕,可怕的是错了还不承认,甚至还进行人身攻击。写程序容易,难的是发现别人程序的漏洞,要不然所谓的黑客就跟你一样满天飞了。
      

  26.   

    我挑出LZ的问题,也给LZ具体分析
    你如果真对线程了解,又岂会看不出问题?连LS的年轻人,指点后都能看出来了。
    你的话本来就不严谨,再见上自己又说认真看了一下,于是下了个结论,应该也是能够得到正确的结果,而且,你还是对我的回帖做的回复,也就是说我在帖子里的都把问题说出来了,你还没看出来,还得出这样的结论,说到这里就不用解释了,你懂的,如此认真还找不出问题?不要以为自己写了个程序就表示自己很牛,不知就是不知。你这属于典型的钻牛角尖,明白的人都知道你的解释很苍白,没看出问题来就是没看出问题来,不用作无谓的解释,你自己也说没仔细推敲会引起问题,既知有问题,又岂能草率下结论?而且对你所谓的能得到正确的结果,我也说过一时的结果正确不代表正确,如果非要说别人挑刺,那我就挑出你的语句问题,应该有时能得到正确的结果,这句话和你那句话,意思可谓差远了。有错不可怕,可怕的是错了还不承认,甚至还进行人身攻击。写程序容易,难的是发现别人程序的漏洞,要不然所谓的黑客就跟你一样满天飞了。厉害,我多线程没怎么入门,要学的东西还有很多啊。