今天看到一个题:两个线程交替打印奇数和偶数,即一个线程打印奇数,另一个打印偶数,交替打印从1到100。想了下有多重实现方法。
wait和notify方法:
1 public class OddEven { 2 3 private static int i = 1; 4 5 private static Object o = new Object(); 6 7 private static class MyThread extends Thread { 8 MyThread(String name) { 9 super(name); 10 } 11 12 public void run() { 13 try { 14 synchronized (o) { 15 while (i < 100) { 16 System.out.println(this.getName() + i++); 17 o.notify(); 18 o.wait(); 19 } 20 o.notify(); 21 } 22 System.out.println(this.getName() + " over"); 23 } catch (Exception e) { 24 e.printStackTrace(); 25 } 26 } 27 } 28 29 public static void main(String[] args) { 30 new MyThread("奇 ").start(); 31 new MyThread("偶 ").start(); 32 33 } 34 }
—
输出:
奇 1
偶 2
奇 3
偶 4
奇 5
偶 6
奇 7
…
LockSupport实现
public class OddEvenLockSupport { private static int i = 1; private static Thread t1 = new MyThread1(); private static Thread t2 = new MyThread2(); public static void main(String[] args) { t1.start(); t2.start(); } private static class MyThread1 extends Thread { @Override public void run() { while (i < 51) { System.out.println("奇 " + i++); LockSupport.unpark(t2); LockSupport.park(); } System.out.println(getName() + " over"); LockSupport.unpark(t2); } } private static class MyThread2 extends Thread { @Override public void run() { while (i < 51) { LockSupport.park();//顺序很重要 System.out.println("偶 " + i++); LockSupport.unpark(t1); } System.out.println(getName() + " over"); LockSupport.unpark(t1); } } }
—
使用Condition
public class OddEven2 { private static Lock lock = new ReentrantLock(); static Condition even_c = lock.newCondition(); static Condition odd_c = lock.newCondition(); private static class Odd extends Thread { public void run() { int odd = 1; try { lock.lock(); while (odd < 100) { System.out.println("奇 " + odd); odd += 2; even_c.signal(); odd_c.await(); } System.out.println("奇 over"); } catch (InterruptedException e) { e.printStackTrace(); } finally { even_c.signal(); lock.unlock(); } } } private static class Even extends Thread { public void run() { int even = 0; try { lock.lock(); while (even < 100) { System.out.println("偶 " + even); even += 2; odd_c.signal(); even_c.await(); } System.out.println("偶 over"); } catch (InterruptedException e) { e.printStackTrace(); } finally { odd_c.signal(); lock.unlock(); } } } public static void main(String[] args) { new Even().start(); new Odd().start(); } }
—
另一个题,写出会导致死锁的代码:
public class DeadLock extends Thread { private Object lock1; private Object lock2; public DeadLock(Object o1, Object o2) { this.lock1 = o1; this.lock2 = o2; } public void run() { synchronized (lock1) { try { TimeUnit.MILLISECONDS.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock2) { Q.p("end"); } } } public static void main(String[] args) { Object o1 = new Object(), o2 = new Object(); new DeadLock(o1, o2).start(); new DeadLock(o2, o1).start(); Q.p("main end"); } }
—
基础回顾:
每个Java对象都拥有一个锁标记,即monitor(监视器),称为对象锁。
wait:
调用obj.wait()方法会阻塞当前线程,直到另一线程调用obj.notify()或obj.notifyAll()方法,其中obj为同一对象,当前线程必须持有obj对象锁,即必须在synchronized方法或代码块中,否则抛出IllegalMonitorStateException。调用wait方法的线程会释放对象锁。
notify:
唤醒一个正在等待该对象锁的线程,若有多个线程都在等待也只会唤醒一个。被唤醒的线程无法立即执行,直到当前线程放弃该对象锁,然后被唤醒的线程会像往常一样与任何其他线程竞争该对象锁,
该方法也必须在持有该对象锁的线程里调用,即必须在synchronized方法或代码块中,否则抛出IllegalMonitorStateException。
synchronized:
synchronized关键字标记一个方法或者代码块,当某个线程调用该对象的synchronized方法或者访问synchronized代码块时,这个线程便获得了该对象的锁,其他线程暂时无法访问这个方法,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁,其他线程才能执行这个方法或者代码块。
end