疯狂java第16章课后习题第一题:用java写两个线程,一个线程打印1-52,另一个线程打印字母A-Z,打印顺序为12A34B。。。5152Z。
于是在Eclipse中根据第一个java文件自己敲出的第二个java文件,二者几乎没有什么区别,可是第一个文件运行成功并正确显示结果,第二个文件运行报错:NoSuchMethodError
1.PrinterCheck.java
1 import java.util.concurrent.locks.*; 2 class Printer 3 { 4 private final Lock lock = new ReentrantLock(); 5 private final Condition cond = lock.newCondition(); 6 private final int[] arrNumber = new int[52]; 7 private int n;//arrNumber计数 8 private final char[] arrChar = new char[26]; 9 private int c;//arrChar计数 10 private int counter;//连续打印数字的间隔 11 //Printer构造器 12 public Printer( ) 13 { 14 for(int i=0;i<arrNumber.length;i++) 15 { 16 arrNumber[i] = (i+1); 17 } 18 for(char i='A';i<'Z'+1;i++) 19 20 21 { 22 arrChar[i-65] = i; 23 } 24 } 25 public void printNumber() 26 { 27 lock.lock(); 28 try 29 { 30 if(counter>1) 31 { 32 cond.await(); 33 } 34 else 35 { if(n>51) return; 36 System.out.print(arrNumber[n]+" "); 37 n++; 38 counter++; 39 cond.signalAll(); 40 } 41 42 } 43 catch (InterruptedException e) 44 { 45 e.printStackTrace(); 46 } 47 finally 48 { 49 lock.unlock(); 50 } 51 } 52 public void printChar() 53 { 54 lock.lock(); 55 try 56 { 57 if(counter<2) 58 { 59 cond.await(); 60 } 61 else 62 { 63 if(c>25) return; 64 System.out.print(arrChar[c]+" "); 65 c++; 66 counter=0; 67 cond.signalAll(); 68 } 69 } 70 catch (InterruptedException e) 71 { 72 e.printStackTrace(); 73 } 74 finally 75 { 76 lock.unlock(); 77 } 78 } 79 } 80 class PrintNumber extends Thread 81 { 82 private Printer print; 83 public PrintNumber(String name,Printer print) 84 { 85 super(name); 86 this.print = print; 87 } 88 public void run() 89 { 90 for(int i=0;i<100;i++) 91 { 92 print.printNumber(); 93 } 94 } 95 } 96 class PrintChar extends Thread 97 { 98 private Printer print; 99 public PrintChar(String name,Printer print) 100 { 101 super(name); 102 this.print = print; 103 } 104 public void run() 105 { 106 for(int i=0;i<100;i++) 107 { 108 print.printChar(); 109 } 110 } 111 } 112 public class PrinterCheck 113 { 114 public static void main(String[] args) throws Exception 115 { 116 Printer print = new Printer(); 117 new PrintNumber("打印数字",print).start(); 118 new PrintChar("打印字符",print).start(); 119 } 120 }
点击运行,结果如下:
2.MulThreadPrint.java
1 import java.util.concurrent.locks.* ;
2 class Printer
3 { //显示定义Lock对象 4 private final Lock lock = new ReentrantLock(); 5 //获得指定Lock对象对应的condition 6 private final Condition cond = lock.newCondition(); 7 //private final int[] arrNumber = new int[52];//保存数字的数组 8 private final int[] arrNumber = new int[52]; 9 private int nNumber;//数字的计数 10 //private final char[] arrChar = new char[26];//保存字符的数组 11 private final char[] arrChar = new char[26]; 12 private int nChar;//字符的计数 13 14 private int nInternal;//数字连续打印的间隔 15 //重写构造器对数组进行初始化赋值 16 public Printer() 17 { 18 for(int i=0;i<arrNumber.length;i++) 19 { 20 arrNumber[i] = i+1; 21 } 22 for(char i='A';i<'Z'+1;i++) 23 { 24 arrChar[i-65] = i; 25 } 26 } 27 //打印数字的方法 28 public void PrintNumber() 29 { //加锁 30 lock.lock(); 31 try 32 { //如果数字连续打印了2个,就暂停等待 33 if(nInternal>1) 34 { 35 cond.await(); 36 } 37 //如果数字连续打印少于2个,就继续打印,打印完数字之后就唤醒其他线程 38 else 39 {
//判断到最后数字时返回退出程序 40 if(nNumber==52) 41 return; 42 System.out.print(arrNumber[nNumber]+" "); 43 nNumber++; 44 nInternal++; 45 cond.signalAll(); 46 47 } 48 } 49 catch (InterruptedException ex) 50 { 51 ex.printStackTrace(); 52 } 53 //用finally块来释放锁 54 finally 55 { 56 lock.unlock(); 57 } 58 } 59 //打印字符的方法 60 public void PrintChar() 61 { 62 lock.lock(); 63 try 64 { 65 if(nInternal<2) 66 { 67 cond.await(); 68 } 69 else 70 {
//判断到最后字符时返回退出程序 71 if(nChar==26) 72 return; 73 System.out.print(arrChar[nChar]+" "); 74 nChar++; 75 nInternal = 0; 76 cond.signalAll(); 77 } 78 } 79 catch (InterruptedException ex) 80 { 81 ex.printStackTrace(); 82 } 83 //用finally块来释放锁 84 finally 85 { 86 lock.unlock(); 87 } 88 } 89 } 90 91 class PrintNumberThread extends Thread 92 { 93 private Printer Printer; 94 public PrintNumberThread(String name,Printer Printer) 95 { 96 super(name); 97 this.Printer = Printer; 98 } 99 public void run() 100 { //这里必须有for循环,不然只打印一轮 101 for(int i=0;i<100;i++) 102 { 103 Printer.PrintNumber(); 104 } 105 } 106 } 107 108 class PrintCharThread extends Thread 109 { 110 private Printer Printer; 111 public PrintCharThread(String name,Printer Printer) 112 { 113 super(name); 114 this.Printer = Printer; 115 } 116 public void run() 117 { 118 for(int i=0;i<100;i++) 119 { 120 Printer.PrintChar(); 121 } 122 } 123 } 124 125 public class MulThreadPrint 126 { 127 public static void main(String[] args) throws Exception 128 { 129 Printer Printer = new Printer(); 130 new PrintNumberThread("打印数字",Printer).start(); 131 new PrintCharThread("打印字符",Printer).start(); 132 } 133 }
点击运行,结果如下:
根据报错,是PrintNumberThread.run函数出错了,而run函数调用的是PrintNumber()函数。但实际上PrintNumber()函数是存在的。
问题原因:因为两个文件在同一个包下,而且两个文件的Printer类重名了,于是得到两个矛盾的Printer.class。将第二个文件的Printer类改个名字,再运行即可得到正确结果。
※这里提供该题的第二种方法,同时也是最优方法:将ncouner去掉,直接以i%2==0来判断连续打印2个数字。
1 class Printer2 2 { 3 private final int[] arrNumber = new int[52];//保存数字的数组 4 private final char[] arrChar = new char[26];//保存字符的数组 5 6 //重写构造器对数组进行初始化赋值 7 public Printer2() 8 { 9 for(int i=0;i<arrNumber.length;i++) 10 { 11 arrNumber[i] = i+1; 12 } 13 for(char i=0;i<arrChar.length;i++) 14 { 15 arrChar[i] = (char)('A'+i); 16 } 17 } 18 //定义一个打印数字的同步方法 19 public synchronized void PrintNumber() 20 { 21 for (int i = 1; i < arrNumber.length+1; i++) 22 { //一开始就打印数字 23 System.out.print(arrNumber[i-1]+" "); 24 try 25 { //每连续打印两个数字后,数字线程就唤醒其他线程并且自己暂停等待 26 if(i%2 == 0) 27 { 28 notifyAll(); 29 wait(); 30 } 31 32 } 33 catch(Exception e) 34 { 35 e.printStackTrace(); 36 } 37 } 38 } 39 40 public synchronized void PrintChar() 41 { 42 for(int i=0;i<arrChar.length;i++) 43 { //一开始就打印字符 44 System.out.print(arrChar[i]+" "); 45 try 46 { //每打印一个字符之后,字符线程就唤醒其他线程并且自己暂停等待 47 notifyAll(); 48 wait(); 49 } 50 catch(Exception e) 51 { 52 e.printStackTrace(); 53 } 54 } 55 } 56 } 57 //打印1-52 58 class PrintThreadNumber extends Thread 59 { 60 private Printer2 Printer; 61 public PrintThreadNumber(Printer2 Printer) 62 { 63 this.Printer = Printer; 64 } 65 public void run() 66 { 67 Printer.PrintNumber(); 68 } 69 } 70 //打印A-Z 71 class PrintThreadChar extends Thread 72 { 73 private Printer2 Printer; 74 public PrintThreadChar(Printer2 Printer) 75 { 76 this.Printer = Printer; 77 } 78 public void run() 79 { 80 Printer.PrintChar(); 81 } 82 } 83 84 85 public class MulThreadCom2 86 { 87 public static void main(String[] args) throws Exception 88 { 89 Printer2 Printer = new Printer2(); 90 // 启动两个线程 91 PrintThreadNumber t1 = new PrintThreadNumber(Printer); 92 PrintThreadChar t2 = new PrintThreadChar(Printer); 93 t1.start(); 94 t2.start(); 95 96 } 97 }