第四节 多线程更多练习题
练习题1:三个线程交替打印数字
启动3个线程打印递增的数字, 线程1先打印1,2,3,4,5 然后是线程2打印6,7,8,9,10 然后是线程3打印11,12,13,14,15.接着再由线程1打印16,17,18,19,20....依次类推, 直到打印到60。
提示:定义一个同步方法,在方法中使用循环的方式输出连续的5个数字,方法执行前,可以通过标记的方式判断是否是当前线程应该执行,如果是,则执行输出逻辑,如果不是,则wait进入等待队列,在方法执行结束前,必须使用notifyAll唤醒其他所有线程。
练习题2:自定义容器
自定义容器,提供新增元素(add)和查看元素(get)方法。add方法向容器末尾位置新增元素,get方法通过参数传递的下标返回对应位置的元素。注意:get方法只读,不会删除对应位置的元素数据。
要求为容器提供读写锁能力。即写写互斥、读写互斥,多线程并发访问当前容器,只能有一个线程做写操作,可以有多个线程同时执行读操作。
读写锁解释:当有任意线程执行写操作,则其他所有线程阻塞等待;当有任意线程执行读操作,则其他所有写线程阻塞,读线程可执行。
提示:定义一个容器类,其中定义一个任意集合类型的属性,提供add方法和get方法。在类中定义一个属性作为写入锁对象,定义一个boolean类型属性用于记录当前容器状态是否是写入状态。定义add方法,方法中定义同步代码块,对写入锁对象加锁。判断容器当前是否是写入状态,如果是在调用锁对象的wait方法,进入等待状态;在同步代码块中将boolean类型属性赋值为true,标记为当前是写入状态,其他线程不可操作容器;在同步代码块执行结束前,将boolean类型属性赋值为false,标记写入结束,其他线程可以操作容器,并且调用锁对象的notifyAll方法唤醒其他所有线程。定义get方法,方法中先使用while循环来判断当前容器是否是写入状态,如果是写入状态,当前线程休眠1毫秒(也称为自旋);如果不是写入状态,则读取容器中对应下标的元素。
练习题3: 3个线程打印递减数字
启动3个线程打印递减数字,范围是:30~1。要求数字不能重复,每个线程打印一个数字后,立刻进入睡眠状态,睡眠时间300毫秒。(模拟多线程售票)
提示:定义一个类,其中定义一个数学类型的属性,用于记录要输出数字的上限(本题目中为30),定义一个方法,用于循环输出数字,循环条件为属性大于0。每次输出数字的时候让记录数字上限的属性自减1。注意,在循环输出的时候,使用try...finally代码块保证try中lock获取锁,finally中释放锁。
练习题4: 生产电脑和搬运电脑
写一个生产电脑和搬运电脑的程序。要求生产出一台电脑就搬走一台电脑。如果新的电脑没有生产出来,则搬运工就要等待;如果生产出的电脑没有搬走,则要等待电脑搬走后再生产。
提示:使用Lock相关技术实现典型的生产者消费者模式