如果要问我Java当中最难的部分是什么?最有意思的部分是什么?最多人讨论的部分是什么?那我会毫不犹豫地说:多线程。
在了解多线程之前,最好先知道什么是并发,什么是并行。不然很容易迷糊。
总的来说,就是这样:
学习多线程最好从如下六个方面循序渐进(纯粹个人经验和建议,可无视):
Java多线程用一句话总结就是「6类5法」。
所谓「6类」,就是多状态的状态分为这6类:
这是线程生命周期的状态变化图:
简单来说,就是这样:
而所谓「5法」就是线程的核心方法是这么5个:
用代码来解释一下会更直观一些。
第一种wait/notify的情况:
public static void main(String[] args) { Thread t1 = new Thread(new Runnable() { @Override public void run() { synchronized ("锁") { System.out.println("t1 start"); try { // t1释放锁 "锁".wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("t1 end"); } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { synchronized ("锁") { System.out.println("t2 start"); try { // 通知t1进入等待队列 "锁".notify(); } catch (Exception e) { e.printStackTrace(); } System.out.println("t2 end"); } } }); t1.start(); t2.start(); }
此时代码执行流程(两种可能):
这里要强调的重点是:
如果说只有两个线程的时候,还能尝试着分析一下结果,那么当有四个线程的时候会如何呢?看看代码:
public static void main(String[] args) { Thread t1 = new Thread(new Runnable() { @Override public void run() { synchronized ("锁") { System.out.println("t1 start"); try { // t1释放锁 "锁".wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("t1 end"); } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { synchronized ("锁") { try { System.out.println("t2 start"); // 随机通知一个等待的线程进入等待队列 "锁".notify(); System.out.println("t2 end"); } catch (Exception e) { e.printStackTrace(); } } } }); Thread t3 = new Thread(new Runnable() { @Override public void run() { synchronized ("锁") { try { System.out.println("t3 start"); // 随机通知一个等待的线程进入等待队列 "锁".notify(); System.out.println("t3 end"); } catch (Exception e) { e.printStackTrace(); } } } }); Thread t4 = new Thread(new Runnable() { @Override public void run() { synchronized ("锁") { try { System.out.println("t4 start"); // t4释放锁 "锁".wait(); System.out.println("t4 end"); } catch (Exception e) { e.printStackTrace(); } } } }); t1.start(); t2.start(); t3.start(); t4.start(); }
然后同时开启这四个线程,但结果是无法预料!为什么?因为只有两种可能的流程(要么wait先执行完,要么notify先执行完),至于每种流程里面怎么执行的?不知道!不清楚!无法预料!这就是多线程让人困惑的地方和魅力所在。
而且线程还有一个无赖的行为就是:虽然你有优先级,但我不保证有用!
public class MyThread extends Thread { MyThread(String s) { super(s); } @Override public void run() { for (int i = 0; i <= 10; i++) { System.out.println(getName() + " : " + i); if (i == 5) { Thread.yield(); } } } public static void main(String[] args) throws InterruptedException { System.out.println("主线程启动"); Thread t1 = new MyThread("t1"); Thread t2 = new MyThread("t2"); t1.setPriority(Thread.MIN_PRIORITY); t1.start(); t2.setPriority(Thread.MAX_PRIORITY); t2.start(); t1.join(); t2.join(); System.out.println("主线程结束"); } }
这里不管怎么设置t1或者t2的优先级,都没有用,运行的结果每次都可能不一样。
线程的生命周期6类5法算是比较简单的,是基础中的基础。但是用好很难,关键在于多练多想,多多尝试各种组合。