学习多线程最好的方法就是敲代码了,可以通过练习几个简单的 Demo 来理解 Java 中的多线程之间的协同工作。
Demo 1:交替打印数值
使用两个线程交替打印数值到 100,也就是说线程A打印1,然后线程B打印2,接着再线程A打印3,……,最后线程B打印100。
首先实现一个 Runnable 类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class Print implements Runnable { private static int i = 1;
@Override public void run() { while (true) { synchronized (this) { notify(); if (i <= 100) { System.out.println(Thread.currentThread().getName() + " print: " + i); ++i;
try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } else { break; } } } } }
|
接着创建线程进行调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public static void main(String[] args) { Print print = new Print(); Thread threadOne = new Thread(print); threadOne.setName("Thread 1"); Thread threadTwo = new Thread(print); threadTwo.setName("Thread 2");
threadOne.start(); threadTwo.start(); }
|
Demo 2:交替打印ABC
使用三个线程交替打印A、B、C,也就是说线程1打印A,然后线程2打印B,接着线程3打印C。和Demo 1 不同的是,现在需要 3 个线程进行协作,因此所需要的对象锁的数量也会增加。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class Print implements Runnable {
private final String name; private final Object prev; private final Object self;
public Print(String name, Object prev, Object self) { this.name = name; this.prev = prev; this.self = self; }
@Override public void run() { int count = 10; while (count > 0) { synchronized (prev) { synchronized (self) { System.out.println("Now printing: " + name); --count; self.notify(); }
try { if (count == 0) { prev.notify(); } else { prev.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } } } }
|
创建线程并启动:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| public static void main(String[] args) throws InterruptedException { Object a = new Object(); Object b = new Object(); Object c = new Object();
Print printA = new Print("A", c, a); Print printB = new Print("B", a, b); Print printC = new Print("C", b, c);
new Thread(printA).start(); Thread.sleep(100); new Thread(printB).start(); Thread.sleep(100); new Thread(printC).start();
}
|
除了使用 synchronized 关键字和对象自带的 wait() 与 notify() 方法来实现外,还可以使用 JUC 包下的 Lock 锁以及 Condition 来实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| public class PrintUseLock {
private static final Lock lock = new ReentrantLock(); private static final Condition A = lock.newCondition(); private static final Condition B = lock.newCondition(); private static final Condition C = lock.newCondition();
private static int count = 0;
static class ThreadA extends Thread { @Override public void run() { try { lock.lock(); for (int i = 0; i < 10; i++) { while (count % 3 != 0) { A.await(); } System.out.println("Now printing: A"); count++; B.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
static class ThreadB extends Thread { @Override public void run() { try { lock.lock(); for (int i = 0; i < 10; i++) { while (count % 3 != 1) { B.await(); } System.out.println("Now printing: B"); count++; C.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }
static class ThreadC extends Thread { @Override public void run() { try { lock.lock(); for (int i = 0; i < 10; i++) { while (count % 3 != 2) { C.await(); } System.out.println("Now printing: C"); count++; A.signal(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } }
|