黑马程序员技术交流社区

标题: java多线程问题 [打印本页]

作者: 289314335    时间: 2016-9-30 23:30
标题: java多线程问题
假设抽奖箱中有100个号码(依次从1到100),开启两个线程, 共随机抽选出10个号码,并在控制台上打印出两个线程分别抽选了哪些号码? 提示:(两个线程不能抽取同一个号码,已经抽取的号码不能再次抽取; 不限定两个线程抽取的个数一样,总共抽选10个即可,线程名自定义)。
问题是,我按照多线程的正规写法用了同步代码块,锁对象也是类的字节码文件,但是输出的时候每次只有一个线程进行输出,用了sleep()方法也切换不了线程,类采用的是继承Thread,怀疑是不是创建了两个Thread,出现了两个对象的问题,但是用了实现runnable接口结果还是一样的。求助哪里出了问题?下面是代码:
public class ChouJiang {

public static void main(String[] args) {
Thread t1 = new Chou();
t1.setName("线程一");
Thread t2 = new Chou();
t2.setName("线程二");

t1.start();
t2.start();
}

}

class Chou extends Thread {
// 100个号码(依次从1到100)

static ArrayList<Integer> list = new ArrayList<Integer>();
static HashSet<Integer> hs = new HashSet<Integer>();
static {

for (int i = 1; i <= 100; i++) {
list.add(i);
}

while (hs.size() < 10) {
Random r = new Random();
int j = r.nextInt(100) + 1; // 随机数获取1-100
hs.add(j);
}
}

@Override
public void run() {
// 共随机抽选出10个号码, 并在控制台上打印出两个线程分别抽选了哪些号码
// * 提示:(两个线程不能抽取同一个号码,已经抽取的号码不能再次抽取;
synchronized (ChouJiang.class) {
while (list.size() > 90) {
for (Integer num : hs) {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName()
+ "抽取了:" + num + "号球");
list.remove(num);
} catch (Exception e) {
}

}

}
}

}

}


作者: Reisen    时间: 2016-9-30 23:30
1.直接new两个Thread子类,就相当于两个抽奖箱了,应该实现Runnable接口作为参数传入Thread
2.sleep方法是不会释放锁的,wait()方法才会,一个线程上锁后会一直执行到while循环读完后才释放锁,此时list.size() == 90不满足条件另一个线程进入直接跳过中间的所有代码...
作者: guhaoa    时间: 2016-10-2 13:41
你还需要解答吗,我可以帮你解决
作者: 读书可以当饭吃    时间: 2016-10-2 14:01
本帖最后由 读书可以当饭吃 于 2016-10-2 14:11 编辑

这是我写的,注释写得不是很清楚,看不懂再问吧
import java.util.ArrayList;
import java.util.Random;
public class Test2 {
        /**
         * 100个数的抽奖箱中由两个线程共随机抽取10个数
         * @throws InterruptedException
         */
        public static void main(String[] args) throws InterruptedException {
                final ArrayList<Integer> list = new ArrayList<>();                //创建抽奖箱
                final ArrayList<Integer> list2 = new ArrayList<>();                //创建存放甲抽得的数的箱子
                final ArrayList<Integer> list3 = new ArrayList<>();                //创建存放乙抽得的数的箱子
                for(int i = 1;i<=100;i++){                //向抽奖箱添加被抽取的数
                        list.add(i);
                }
                final Random ra = new Random();        //创建生成随机数对象
                Runnable r = new Runnable() {        //创建Runnable接口子类对象
                        int y = 100;                //用于记录抽奖箱剩余的数有多少个
                        int z = 0;                        //用于记录抽取了多少个数
                        public void run() {
                                while(true){
                                        synchronized (list) {        //加锁保证线程同步,不会重复抽取
                                                if(z<10){
                                                        //随机产生一个1-y范围内的整数x
                                                        int x = ra.nextInt(y)+1;
                                                        //从list集合中删除索引为x的元素并用in记录
                                                        Integer in = list.remove(x);
                                                        //如果线程名为"甲",则将删除的元素添加到list2集合
                                                        if("甲".equals(Thread.currentThread().getName())){
                                                                list2.add(in);
                                                        }else if("乙".equals(Thread.currentThread().getName())){
                                                                list3.add(in);
                                                        }
                                                        //集合长度变短,对应的求索引的范围应该变小
                                                        y--;
                                                        //记录抽取了多少个元素
                                                        z++;
                                                }else{
                                                        return;                //抽出10则结束线程
                                                }
                                        }
                                }
                        }
                };
                Thread t1 = new Thread(r);        //传入Runnable接口子类对象创建线程
                Thread t2 = new Thread(r);
                t1.setName("甲");        //设置线程名字
                t2.setName("乙");
                t1.start();                //开启线程
                t2.start();
                t1.join();                //主线程等待t1线程完成后执行
                t2.join();
                System.out.println(t1.getName()+"抽取了:"+list2);
                System.out.println(t2.getName()+"抽取了:"+list3);
        }
        
}

作者: fdzx0707fh    时间: 2016-10-4 20:03
**********synchronized (ChouJiang.class)******
这个锁用错了 ,你换成this就可以了

作者: fdzx0707fh    时间: 2016-10-4 20:06
fdzx0707fh 发表于 2016-10-4 20:03
**********synchronized (ChouJiang.class)******
这个锁用错了 ,你换成this就可以了

synchronized(ThreadTest.class)是对ThreadTest这个类进行加锁,类里面的属性,方法都是同步的,是针对于特定的类的~~

synchronized(this){}是对{}这里面的内容进行加锁的,仅仅是针对于当前对象的
作者: wangkai426    时间: 2016-10-6 22:20
线程安全问题比较头疼




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2