我的问题:三个线程的ID分别是A,B,C;,每个线程将自己的ID值在屏幕上打印5遍,打印顺序是ABCABC。
我编写的代码:
package 并发编程.work2; public class Test { private static volatile String CURRENT_THREAD = "A"; public static void main(String[] args) { Thread t1 = new Thread(new PrintThreadName(), "A"); Thread t2 = new Thread(new PrintThreadName(), "B"); Thread t3 = new Thread(new PrintThreadName(), "C"); t1.start(); t2.start(); t3.start(); } static class PrintThreadName implements Runnable { @Override public void run() { for (int i = 0; i < 5; i++) { synchronized (CURRENT_THREAD) { // 从A开始 while (!CURRENT_THREAD.equals(Thread.currentThread().getName())) { try { CURRENT_THREAD.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.print(CURRENT_THREAD); // 线程打印完毕后,设置下一个要打印的线程标识,并唤醒其他线程 if (CURRENT_THREAD.equals("A")) { CURRENT_THREAD = "B"; } else if (CURRENT_THREAD.equals("B")) { CURRENT_THREAD = "C"; } else if (CURRENT_THREAD.equals("C")) { CURRENT_THREAD = "A"; } CURRENT_THREAD.notifyAll(); } } } } }
但是出现了错误
主要的问题是:
// 线程打印完毕后,设置下一个要打印的线程标识,并唤醒其他线程 if (CURRENT_THREAD.equals("A")) { CURRENT_THREAD = "B"; } else if (CURRENT_THREAD.equals("B")) { CURRENT_THREAD = "C"; } else if (CURRENT_THREAD.equals("C")) { CURRENT_THREAD = "A"; }
你使用一个volatile修饰的字符串CURRENT_THREAD来充当锁的角色
但是却在锁对象释放自己拥有的锁之前就把锁的引用给修改了
也就会出现 现在的锁对象其实已经被修改了(它是没有锁的 锁在之前的对象身上)
你还要让它释放锁 属于是强人所难了 所以会报错
这个错误产生的原因是某一线程在等待其他线程释放锁 但是突然要求它释放锁 它还在等呢怎么会有锁 所以就会抛出IllegalMonitorStateException
解决方法就是额外使用另一个锁对象来实现同步 不要在锁对象释放锁之前对它进行任何修改 可以参照楼上的方案
package 并发编程.work2; public class Test { private static final Object lock = new Object(); private static volatile String CURRENT_THREAD = "A"; public static void main(String[] args) { Thread t1 = new Thread(new PrintThreadName(), "A"); Thread t2 = new Thread(new PrintThreadName(), "B"); Thread t3 = new Thread(new PrintThreadName(), "C"); t1.start(); t2.start(); t3.start(); } static class PrintThreadName implements Runnable { @Override public void run() { for (int i = 0; i < 5; i++) { synchronized (lock) { // 从A开始 while (!CURRENT_THREAD.equals(Thread.currentThread().getName())) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.print(CURRENT_THREAD); // 线程打印完毕后,设置下一个要打印的线程标识,并唤醒其他线程 if (CURRENT_THREAD.equals("A")) { CURRENT_THREAD = "B"; } else if (CURRENT_THREAD.equals("B")) { CURRENT_THREAD = "C"; } else if (CURRENT_THREAD.equals("C")) { CURRENT_THREAD = "A"; } lock.notifyAll(); } } } } }