这道题我大概搞了两个小时左右吧。
可是我发现总是不对,最后发现我做不出来了,因为我并未真正搞清整个程序的执行,以及对那些关键词(我指的是synchronized、wait()、notify()等这些玩意儿)的理解和使用都不清楚,更别说写出来整个程序了。
public class Forth2 {
public static void main(String[] args) {
MyRunnable3 mr = new MyRunnable3();
Thread t1 = new Thread(mr, "Thread1");
Thread t2 = new Thread(mr, "Thread2");
Thread t3 = new Thread(mr, "Thread3");
Thread t4 = new Thread(mr, "Thread4");
Thread t5 = new Thread(mr, "Thread5");
Thread t6 = new Thread(mr, "Thread6");
Thread t7 = new Thread(mr, "Thread7");
Thread t8 = new Thread(mr, "Thread8");
Thread t9 = new Thread(mr, "Thread9");
Thread t10 = new Thread(mr, "Thread10");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
t8.start();
t9.start();
t10.start();
mr.printSum();
}
}
class MyRunnable3 implements Runnable {
static int[] sum = new int[10];
static int[] thread = {1, 11, 21, 31, 41, 51, 61, 71, 81, 91};
public synchronized void run() {
while (true) {
if (!Thread.currentThread().getName().equals("Thread1")) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if (thread[0] <= 10)
{
sum[0] += thread[0]++;
this.notifyAll();
}
if (!Thread.currentThread().getName().equals("Thread2")) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if (thread[1] < 20)
{
sum[1] += thread[1]++;
this.notifyAll();
}
if (!Thread.currentThread().getName().equals("Thread3")) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else if (thread[2] <= 30)
{
sum[2] += thread[2]++;
this.notifyAll();
}
//下面的是未修改为上面做法的时候,知道全部修改后也不对,所以放弃修改了。。。
if (Thread.currentThread().getName() == "Thread4") {
if (thread[3] <= 40)
sum[3] += thread[3]++;
}
if (Thread.currentThread().getName() == "Thread5") {
if (thread[4] < 50)
sum[1] += thread[4]++;
}
if (Thread.currentThread().getName() == "Thread6") {
if (thread[5] <= 60)
sum[2] += thread[5]++;
}
if (Thread.currentThread().getName() == "Thread7") {
if (thread[6] <= 70)
sum[0] += thread[6]++;
}
if (Thread.currentThread().getName() == "Thread8") {
if (thread[7] < 80)
sum[1] += thread[7]++;
}
if (Thread.currentThread().getName() == "Thread9") {
if (thread[8] <= 90)
sum[2] += thread[8]++;
}
if (Thread.currentThread().getName() == "Thread10") {
if (thread[9] <= 100)
sum[2] += thread[9]++;
}
}
}
public void printSum() {
System.out.println(sum[0]);
System.out.println(sum[1]);
System.out.println(sum[2]);
System.out.println(sum[3]);
System.out.println(sum[4]);
System.out.println(sum[5]);
System.out.println(sum[6]);
System.out.println(sum[7]);
System.out.println(sum[8]);
System.out.println(sum[9]);
System.out.println(sum[0] + sum[1] + sum[2] + sum[3] + sum[4] + sum[5] + sum[6] + sum[7] + sum[8] + sum[9]);
}
}
看了正确答案后,有以下感想:
1、没有完全把握住封装思想,没有养成在写程序前先进行思考的习惯:
对于每一组的相加操作,应该找到规律,然后将其封装为一个方法!这样会使得程序更加简单。
2、join()的必要:通过for循环中的join()可以确保这十个线程全部执行完后,再执行主线程的打印语句,否则,十一个线程(10+主线程)的执行顺序是不确定的,这会使得最后的打印结果出错。
【注意:虽然有for循环依次执行每个线程的join,也就是说创建的十个线程依次插入到执行序列上,但每一组的打印结果并非是按照顺序有小到大的打印出来。因为可能在此之前就已经执行完了这个线程(也就是说,这时候已经打印出了该组的和sum),所以当它执行到join语句时,它从上次线程停止的地方继续执行,但已经发现自己不符合run的执行条件了,所以,join语句对处于这种情况的线程没有影响。只有调用join的线程还可以继续在被执行时,join才真正起到了作用——让该线程一直执行,直至不符合条件为止,期间不允许其他线程插入。这样,每一组的结果的打印顺序实际上是随机的呢。】
【也可以这样理解:一共十一个线程,这十一个线程其实总是随机执行的(取决于CPU给谁执行机会),但是我们想要的结果是让我们创建的那十个线程正确执行出结果,最后执行一次主线程的打印语句就完事。于是,我们在主线程上加了join语句,让这十个线程都插一次队,执行完了的线程就没啥事了,没执行完了的就继续执行,直至不符合run中的条件。最后,主线程输出最后的结果。】
package chapcter5;
public class Accumulator extends Thread {
/*可以直接让主函数所在的类继承Thread类!
* 可以理解为,对于这道题的解答,直接放在了一个类里。
*
* */
private int startNum;
public static int sum;
public Accumulator(int startNum) {
this.startNum = startNum;
}
public static synchronized void add(int num) { //add()被设置为线程安全的!该方法不能被多个线程同时执行!
sum += num;
}
public void run() {
int sum = 0;
for (int i = 0; i < 10; i++) {
sum += (startNum + i); //找到规律...
/* 执行效果:(这是自己不容易想到的。所以在写程序前要思考!寻找每组连加的规律!才能使代码变得简单啊)
* 第一组:0 + (1+0)+(1+1)+(1+2)+...+(1+9) = 1 + 2 + 3 + ... + 10
* 第二组:0 + (11+0) +(11+1)+(11+2)+...+(11+9) = 11 + 12 + 13 + ... + 20
* ...
* */
}
System.out.println(sum);
add(sum); //将每组的结果相加
}
public static void main(String[] args) {
Thread[] threadList = new Thread[10]; //创建Thread数组!
for (int i = 0; i < 10; i++) { //这个for循环的作用是开启十个线程!
threadList[i] = new Accumulator(10 * i + 1);//找到技巧...
/* 这里将分别传入每组的初始数据。
* */
threadList[i].start();
}
for (int i = 0; i < 10; i++) {
try {
threadList[i].join();
/*
* 谁调用join()谁就优先执行。也就是说,threadList[i]线程一直执行自己的run()方法,直至不符合条件使得该线程结束。
* 事实上,在此之前每个线程执行到何种地步是不需要关心的。而这里的for循环可以确保每个线程都执行完了。
* 那么这个for循环语句的执行顺序是:先i = 0,使得threadList[0]一直执行其run()直至完毕后,再使得i = 1...这样进行下去???
*
* */
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //
}
System.out.println("1 + 2 + 3 + ... + 100 = " + sum);
}
}