首页 > 试题广场 >

Which two statements are true

[不定项选择题]
public class NameList
{
    private List names = new ArrayList();
    public synchronized void add(String name)
    {
        names.add(name);
    }
    public synchronized void printAll() {
        for (int i = 0; i < names.size(); i++)
        {
            System.out.print(names.get(i) + "");
        }
    }

    public static void main(String[]args)
    {
        final NameList sl = new NameList();
        for (int i = 0; i < 2; i++)
        {
            new Thread()
            {
                public void run()
                {
                    sl.add("A");
                    sl.add("B");
                    sl.add("C");
                    sl.printAll();
                }
            } .start();
        }
    }
}

下面正确的2项是?

  • 运行的时候可能抛异常
  • 运行的时候可能没有输出,也没有正常退出
  • 代码运行的时候可能没有输出,但是正常退出
  • 代码输出"A B A B C C "
  • 代码输出"A B C A B C A B C "
  • 代码输出"A A A B C A B C C "
  • 代码输出"A B C A A B C A B C "
在每个线程中都是顺序执行的,所以sl.printAll();必须在前三句执行之后执行,也就是输出的内容必有(连续或非连续的)ABC。
而线程之间是穿插执行的,所以一个线程执行 sl.printAll();之前可能有另一个线程执行了前三句的前几句。
E答案相当于线程1顺序执行完然后线程2顺序执行完。
G答案则是线程1执行完前三句add之后线程2插一脚执行了一句add然后线程1再执行 sl.printAll();输出ABCA。接着线程2顺序执行完输出ABCABC
输出加起来即为ABCAABCABC。
编辑于 2017-08-23 08:45:19 回复(51)
两个线程 线程内部的代码顺序执行,
线程做的事:把 ABC加进去,之后打印
所以不管哪个线程先执行到打印语句,该线程必然已经执行过add ABC了,
所以第一次打印的时候至少有ABC
另一个线程执行到打印语句,list里面必然是两个ABC
发表于 2018-07-29 15:36:25 回复(0)
除了主线程,两个线程的任务都是各种向集合中添加A,B,C这三个元素,但是这两个线程是交替执行的,可以确定的是,第一个执行打印的线程打印的元素至少有三个,且A,B,C是至少各一个的(因为针对某一个线程来说,他它只有添加完三个元素才能打印),第二个执行打印的线程回打印出集合中所有的元素,即6个元素。凭这两个条件就可以得出结论
发表于 2017-10-18 10:46:33 回复(0)
看到ruin所以没选的。。。
发表于 2016-07-20 16:21:49 回复(0)
第一次println的字符个数肯定大于等于3,小于等于6;第二次println的字符个数肯定等于6;所以输出的字符中,后6位肯定是第二次输出的,前面剩下的就是第一次输出的。而且第一次的输出结果肯定是第二次输出结果的前缀。所以选E、G。
发表于 2015-09-04 23:46:19 回复(34)
跑了原程序,一直输出 ABCABCABC,不知道哪两个大案怎么来的,瞎胡闹吗
发表于 2015-07-31 15:05:05 回复(12)
这个题目的结果是有规律的: 规律如下: 1 第一个线程输出的元素个数大于等于3个,小于等于6个。 2 第二个线程(最后执行的线程)输出的元素个数必须等于6个。 3 输出的所有元素中取出最后6个,剩下的元素的顺序和最后6个的顺序相同(从头往后比较)。 如:AABBCCAABBCC 取出最后6个AABBBCC剩下的元素顺序和这个一样。还有我执行的结果 A B A C B C A B A C B C 最后6个元素ABACBC,剩下的元素顺序也一样。还有ABCAABCABC取出最后6个元素,剩下ABCA顺序也一样。 有了这样的规律,可以很容易的判断出输出的是否正确。 其实这个规律的原理很简单,只要注意,线程内顺序执行,线程间交叉执行。 手机写的,写了好几次都没了。还有就是客户端刷新慢,前面一个连着点了好几次。
编辑于 2015-09-08 00:27:40 回复(9)
为什么我电脑只能输出E那个选项?答案错了,只能是ABCABCABC,因为ABC和print语句是一个整体,最后结果只能是ABCABCABC,可能是线程1增加了第一个ABC,也可能线程2增加了第一个ABC,总之第一次输出肯定是ABC,第二次肯定是ABCABC
编辑于 2017-08-04 11:52:34 回复(4)
思考了很久,感觉线程真的很烧脑。。。
首先,我们要知道题中的集合s1是不可变的
然后按照正常思维来讲,第一次线程t1运行,添加然后打印ABC,然后执行第二个线程添加ABC,此时s1中就有两个ABC了,打印出ABCABC. 结果就是ABCABCABC。这应该是没有疑问的
但是由于线程之间执行顺序的不确定性
可以在t1添加完ABC后,要执行打印之前,t2执行了一次(可以是一次到三次)添加操作A
那么此时s1中就有ABCA 打印出的也就是ABCA
然后t1之行结束,t2继续执行添加BC.然后s1变成ABCABC。所以打印处ABCABC,总的结果就是ABCAABCABC

以上是根据结果来判断,总结一下的话可以得出:
第一次打印的长度不可变,但是在3~6之间
第二次打印集合中一定是6个元素,长度也就是6
至于具体的顺序排列组合我也不能全部列举
个人想法,有待思考
发表于 2016-09-16 15:39:29 回复(4)
线1占领add锁,执行ABC后释放锁==>线2占领add锁执行ABC,期间线1占领printAll锁输出==>所以线1按序输出3到6个元素(ABC...)==>
线1执行完printAll方法后释放锁,线2执行printAll并占领锁,此时add已执行完==>所以依次输出6个元素(ABCABC)
发表于 2016-03-24 15:31:08 回复(12)
首先最主要的是,有两条进程在同时进行,线程内的是顺序进行,线程之间的顺序不定,可能是交叉执行,也有可能是先执行了一个线程后执行了另一个线程。但是无论怎样,两个线程不可能同时执行一个操作,这就说明 执行慢的那个线程s1.println();这行代码将会打印出完整的6个字符的字串(但是两个进程添加顺序不确定,有可能是ABCABC,也有可能最后字串是AABBCC或ABABCC等),这就意味着最后6个字符就是真正的添加顺序。

根据逻辑判断,第一次s1.println()结束时,可能两个线程添加都已经添加完,此时第一次s1.println()输出字符最多6个,第二次s1.println()输出字符个数是6个,也就是最多输出12个。
最少的情况,也就是s1.println()结束时,只有第一个线程进行了add()操作,此时字符输出最少3个,第二次是6个,也就是9个。
也就是输出的字符串个数一定在9~12个之间。所以A、B、C、D排除。

所以看选项E的话,最后字串是ABCABC,那第一次s1.println()操作可能在第一个s1.add("c")操作结束到第二个s1.add("c")操作之间。比如:(ABC)ABCABC、(ABCA)ABCABC、(ABCAB)ABCABC、(ABCABC)ABCABC。这些都是可能的输出,所以G也正确。所以E、G正确

而选项F。最后6个字符是BCABCC。首先这不可能,因为虽然添加字符顺序是不确定的,但是确定的是第一个添加的字符肯定是A,并且字符串必须由2个A、2个B、2个C组成。
编辑于 2016-08-19 10:57:35 回复(4)
G答案的执行顺序可以是:
线程一:A、B、C
线程二:A
线程一:printAll(),输出A B C A
线程二:B、C
线程二:printAll(),输出A B C A B C
故总得输出为  A B C A A B C A B C
发表于 2015-09-01 00:53:25 回复(3)
       E:第一个线程一直占用CPU,此时names中是“ABC”,输出“ABC”,然后第二个线程开始执行,又向names中顺序插入了“ABC”,此时names中是“ABCABC”,第二个线程输出“ABCABC”,合在一起就是“ABCABCABC”。
       G:第一个线程先占用CPU一直执行到s1.add("C"),names为“ABC”,第二个线程抢占CPU取得锁(此时第一个线程还没有输出),向names中插入“A”后,names为“ABCA”,此时又被第一个线程重新抢占,输出names中的内容,为“ABCA”,第一个线程结束,第二个线程继续执行,插入“BC”,names为“ABCABC”,输出“ABCABC”,合一起就是“ABCAABCABC”。
发表于 2017-09-02 21:32:59 回复(4)
final NameList sl =new NameList();表示的是NameList这个索引指向的地址值不变,所以,run方法中的操作是向sl中累计添加元素
发表于 2019-02-28 15:56:13 回复(0)

将其他几位的解释自己理解了一下。大概是这样的。

1、首先明确这是两个线程(这里命名为线程1和线程2)打印问题
2、明确线程内是顺序执行,线程间是交叉执行
3、首先是理想情况的分析

线程1顺利执行完后线程2继续执行,那么此时的情况就是:线程1连续add这A,B,C,然后立即打印出A B C;接下来线程2继续执行,即继续add这A,B,C,那么此时的List中的元素就变成了A B C A B C,最后立即打印,那么结果就是E答案所示。

称之为理想情况的原因是线程不打架,顺序执行不混乱,也是打印出最短的情况。

4、剩余的情况,那就是都是交叉的了

来看看可能发生的情况吧。线程1执行add方法,即拿到add锁,在add(A)完成之后,将add锁释放,然后线程1再拿到add锁,add(B)之后释放锁,最后线程1又拿到add锁,add(C)之后,释放add锁。此时,之前三个步骤都是理想情况,下面,按照理想情况,线程1应该拿到printAll()的锁,但是很遗憾,被线程2抢了,他按照线程内的执行顺序,是执行第一个add()方法,add了一个A之后,释放add锁,下面一步又被线程2抢到了printAll()的锁,所以这个时候打印结果是 A B C A,ok,此时线程1以及执行完毕了,下面就顺序执行线程2了,那么继续add(B),add(C),此时List集合中元素又变成了A B C A B C,最后打印结果就是 A B C A  A B C A B C.

5、总结

由于线程之间的交叉执行,最糟糕的情况莫过于在线程1执行打印之前,线程2已经全部执行完毕,举个例子,比如在线程1执行add(A)之后,线程2后面连续抢到锁,将所有的add都执行完,然后线程1再理解执行剩下的两个add,那么线程1的打印结果就是 AABCBC,后面线程2再执行,就是打印两次A (A B C) B C,即12个字母。所以最短打印9个字母,最长打印12个字母。 根据以上分析,这个结论显而易见了:

本题正确的输出一定要符合以下几点:1.第一次输出的元素个数大于等于3个,小于等于6个。 2.第二次(最后执行的线程)输出的元素个数必须等于6个。3.第二次输出的最后6个元素所构成的集合必须为两个A、两个B、两个C。

编辑于 2018-01-07 21:24:51 回复(0)
   两个线程,其中add可能是穿插执行的,可能其中一个线程没执行完add另外一个线程就print了,但是当执行print的时候肯定有个线程add完了~那么输出里面肯定会有个C,并且在第二次执行print的时候会再次将list打印,那么第一次print出来的会再一次print并加上新add的东西(当然也可能完全add完再print)
     所以,D,F肯定不对了,因为它没有重复输出第一次到C的部分
     E是对的,第一个线程add完并执行print的输出了ABC,第二次执行print输出ABCABC,加起来就是ABCABCABC
     G同理,第一个线程执行完add之后第二个线程又add了个A,然后第一个线程print了ABCA,第二个线程add完毕之后printABCABC,加起来就是了~
编辑于 2015-11-24 14:43:21 回复(0)
为什么我把代码跑了那么多次,始终是‘A B C A B C A B C’
发表于 2018-09-28 15:44:29 回复(5)

publicsynchronizedvoidadd(String name),publicsynchronizedvoidprintAll():
这道题中的synchronized只保证在add方法或者printAll方法中对象不会被其他线程调用,但是一旦一个方法调用结束,对象的锁将被释放,其他线程的add方法也可能会访问s1

发表于 2016-06-09 18:02:58 回复(0)
首先应当明确  ,打印发生在至少添加了一次或两次ABC,而且第一次打印长度至少为3,第二次打印长度一定为6,而且第二次打印的顺序一定是ABCABC这种情况。所以这个打印的结果一定是A(X1)B(X2)C(X3)ABCABC。Xi的取值是集合{ABC}的子集(这个说法不一定准确,可以自己体会一下)。这道题的结果 后六位必须是ABCABC 所以只能选E G
编辑于 2015-07-03 19:10:23 回复(6)
在每个线程中都是顺序执行的,所以sl.printAll();必须在前三句执行之后执行,也就是输出的内容必有(连续或非连续的)ABC。
而线程之间是穿插执行的,所以一个线程执行 sl.printAll();之前可能有另一个线程执行了前三句的前几句。
E答案相当于线程1顺序执行完然后线程2顺序执行完。
G答案则是线程1执行完前三句add之后线程2插一脚执行了一句add然后线程1再执行 sl.printAll();输出ABCA。接着线程2顺序执行完输出ABCABC
输出加起来即为ABCAABCABC。
发表于 2022-04-05 19:55:07 回复(0)