- 尽管多线程启动时是有顺序的(通常是for循环),但真正运行起来后,其实没有完全的先后顺序
起10个线程 Test test = new Test(); for (int i = 0; i < 10; i++) { Thread thread = new Thread(test, "thread-" + i); thread.start(); }
|
看执行: thread-1:a:10 thread-1:b:3 thread-4:a:11 thread-4:b:3 thread-6:a:12 thread-6:b:7
|
public void doWrite() { log.info("start to a++"); a++; log.info("a++ finihed"); log.info("start to b++"); b++; log.info("b++ finished");
}
public void print() { System.out.println("" + Thread.currentThread().getName() + ":a:" + a); System.out.println("" + Thread.currentThread().getName() + ":b:" + b); }
public void run() { for (int i = 0; i < 10; i++) { doWrite(); print();
}
|
执行结果: 发现各线程的方法很难完整从到尾一气呵成的执行,证明多线程是基于语句的而不是基于方法的 [INFO ] 2010-05-21 17:10:05,312 thread-0 start to a++ [INFO ] 2010-05-21 17:10:05,312 thread-9 start to a++ [INFO ] 2010-05-21 17:10:05,312 thread-9 a++ finihed [INFO ] 2010-05-21 17:10:05,312 thread-9 start to b++ [INFO ] 2010-05-21 17:10:05,312 thread-9 b++ finished thread-9:a:2 thread-9:b:1 thread-5:b:3 [INFO ] 2010-05-21 17:10:05,328 thread-3 start to a++ 线程3的a++被线程1打断 [INFO ] 2010-05-21 17:10:05,312 thread-1 start to a++ [INFO ] 2010-05-21 17:10:05,328 thread-1 a++ finihed [INFO ] 2010-05-21 17:10:05,328 thread-1 start to b++ [INFO ] 2010-05-21 17:10:05,328 thread-1 b++ finished thread-1:a:8 thread-1:b:6 [INFO ] 2010-05-21 17:10:05,328 thread-3 a++ finihed 直到此句线程3的a++ 才执行完 [INFO ] 2010-05-21 17:10:05,328 thread-3 start to b++ [INFO ] 2010-05-21 17:10:05,328 thread-3 b++ finished
|
- 加了sleep/intercept的多线程: 各线程竞争更合理更有序
public void doWrite() { log.info("start to a++"); a++; log.info("a++ finihed"); try { sleep((int) (Math.random() * 100)); } catch (InterruptedException e) { }
log.info("start to b++"); b++; log.info("b++ finished"); try { sleep((int) (Math.random() * 100)); } catch (InterruptedException e) { } }
|
各线程的语句执行情况大为改观 尽管各线程仍存在竞争,各线程方法仍很难完整执行 但加了sleep/interrupted后,等于增加了调度功能,各线程竞争更合理,更有序
[INFO ] 2010-05-21 17:20:00,593 thread-6 start to a++ [INFO ] 2010-05-21 17:20:00,593 thread-6 a++ finihed [INFO ] 2010-05-21 17:20:00,593 thread-1 start to a++ [INFO ] 2010-05-21 17:20:00,609 thread-1 a++ finihed [INFO ] 2010-05-21 17:20:00,593 thread-4 start to a++ [INFO ] 2010-05-21 17:20:00,593 thread-2 start to a++ [INFO ] 2010-05-21 17:20:00,609 thread-2 a++ finihed [INFO ] 2010-05-21 17:20:00,593 thread-0 start to a++ [INFO ] 2010-05-21 17:20:00,609 thread-3 start to a++ [INFO ] 2010-05-21 17:20:00,609 thread-3 a++ finihed [INFO ] 2010-05-21 17:20:00,609 thread-4 a++ finihed [INFO ] 2010-05-21 17:20:00,609 thread-8 start to a++ [INFO ] 2010-05-21 17:20:00,609 thread-5 start to a++ [INFO ] 2010-05-21 17:20:00,609 thread-5 a++ finihed [INFO ] 2010-05-21 17:20:00,609 thread-0 a++ finihed [INFO ] 2010-05-21 17:20:00,609 thread-7 start to a++ [INFO ] 2010-05-21 17:20:00,609 thread-7 a++ finihed [INFO ] 2010-05-21 17:20:00,609 thread-8 a++ finihed [INFO ] 2010-05-21 17:20:00,609 thread-9 start to a++ [INFO ] 2010-05-21 17:20:00,609 thread-9 a++ finihed [INFO ] 2010-05-21 17:20:00,609 thread-0 start to b++ [INFO ] 2010-05-21 17:20:00,609 thread-0 b++ finished [INFO ] 2010-05-21 17:20:00,609 thread-8 start to b++ [INFO ] 2010-05-21 17:20:00,609 thread-8 b++ finished [INFO ] 2010-05-21 17:20:00,609 thread-2 start to b++ [INFO ] 2010-05-21 17:20:00,609 thread-2 b++ finished [INFO ] 2010-05-21 17:20:00,625 thread-3 start to b++ [INFO ] 2010-05-21 17:20:00,625 thread-3 b++ finished [INFO ] 2010-05-21 17:20:00,640 thread-5 start to b++ [INFO ] 2010-05-21 17:20:00,640 thread-5 b++ finished [INFO ] 2010-05-21 17:20:00,640 thread-1 start to b++ [INFO ] 2010-05-21 17:20:00,640 thread-1 b++ finished thread-3:a:10 thread-3:b:6 [INFO ] 2010-05-21 17:20:00,656 thread-3 start to a++ [INFO ] 2010-05-21 17:20:00,656 thread-3 a++ finihed thread-1:a:11 thread-1:b:6 [INFO ] 2010-05-21 17:20:00,656 thread-1 start to a++ [INFO ] 2010-05-21 17:20:00,656 thread-1 a++ finihed thread-8:a:12 thread-8:b:6 [INFO ] 2010-05-21 17:20:00,671 thread-8 start to a++ [INFO ] 2010-05-21 17:20:00,671 thread-8 a++ finihed thread-0:a:13 thread-0:b:6 [INFO ] 2010-05-21 17:20:00,671 thread-0 start to a++ [INFO ] 2010-05-21 17:20:00,671 thread-0 a++ finihed [INFO ] 2010-05-21 17:20:00,671 thread-9 start to b++ [INFO ] 2010-05-21 17:20:00,671 thread-9 b++ finished [INFO ] 2010-05-21 17:20:00,671 thread-4 start to b++ [INFO ] 2010-05-21 17:20:00,671 thread-4 b++ finished [INFO ] 2010-05-21 17:20:00,671 thread-3 start to b++ [INFO ] 2010-05-21 17:20:00,671 thread-3 b++ finished thread-4:a:14 thread-4:b:9 [INFO ] 2010-05-21 17:20:00,671 thread-4 start to a++ [INFO ] 2010-05-21 17:20:00,671 thread-4 a++ finihed [INFO ] 2010-05-21 17:20:00,687 thread-7 start to b++ [INFO ] 2010-05-21 17:20:00,687 thread-7 b++ finished [INFO ] 2010-05-21 17:20:00,687 thread-6 start to b++ [INFO ] 2010-05-21 17:20:00,687 thread-6 b++ finished thread-2:a:15 thread-2:b:11 [INFO ] 2010-05-21 17:20:00,703 thread-2 start to a++ [INFO ] 2010-05-21 17:20:00,703 thread-2 a++ finihed [INFO ] 2010-05-21 17:20:00,703 thread-1 start to b++ [INFO ] 2010-05-21 17:20:00,703 thread-1 b++ finished [INFO ] 2010-05-21 17:20:00,718 thread-0 start to b++ [INFO ] 2010-05-21 17:20:00,718 thread-0 b++ finished [INFO ] 2010-05-21 17:20:00,718 thread-2 start to b++ [INFO ] 2010-05-21 17:20:00,718 thread-2 b++ finished
|
class Thread的静态属性: static int MAX_PRIORITY static int MIN_PRIORITY static int NORM_PRIORITY
** Thread.MAX_PRIORITY = 10 ** Thread.NORM_PRIORITY = 5 ** Thread.MIN_PRIORITY = 1
主方法main()的优先级是NORM_PRIORITY
| 例子:
public static void main(String[] args) { MyThread mt = new MyThread(); Thread t1 = new Thread(mt, "线程A"); Thread t2 = new Thread(mt, "线程B"); Thread t3 = new Thread(mt, "线程C"); t1.setPriority(Thread.NORM_PRIORITY); // 将线程A设置为中等优先级,缺省为5 t3.setPriority(Thread.MAX_PRIORITY); // 将线程C设置为最高优先级,缺省为10 t2.setPriority(Thread.MIN_PRIORITY); // 将线程B设置为最低优先级,缺省为1 t1.start(); t2.start(); t3.start();
|
运行: D:\java\source\thread\test1>java prioritydemo.PriorityDemo01 线程A线程正在运行。 线程C线程正在运行。 线程B线程正在运行。 线程C线程正在运行。 线程A线程正在运行。 线程B线程正在运行。 线程C线程正在运行。 线程A线程正在运行。 线程B线程正在运行。 线程C线程正在运行。 线程A线程正在运行。 线程B线程正在运行。 线程C线程正在运行。 线程A线程正在运行。 线程B线程正在运行。 线程C线程正在运行。 线程A线程正在运行。
|
计算方法doWrite()上加了synchronized
public synchronized void doWrite() { log.info("start to a++"); a++; log.info("a++ finihed"); try { sleep((int) (Math.random() * 100)); } catch (InterruptedException e) { }
log.info("start to b++"); b++; log.info("b++ finished"); try { sleep((int) (Math.random() * 100)); } catch (InterruptedException e) { } }
public void print() { System.out.println("" + Thread.currentThread().getName() + ":a:" + a); System.out.println("" + Thread.currentThread().getName() + ":b:" + b); }
public void run() { for (int i = 0; i < 10; i++) { doWrite(); print(); }
|
doWrite()已经可以完整执行了,尽管它仍容易被打断,但只会被其他方法打断,不会被其它线程的doWrite()方法打断 方法执行被打断是肯定了,因为线程是基于语句的,不是基于方法的 synchronized是阻止别的线程同一时刻调用本方法,而不是阻止别的线程的别的方法(不是本方法)打断本方法
[INFO ] 2010-05-21 17:48:34,343 thread-0 start to a++ [INFO ] 2010-05-21 17:48:34,343 thread-0 a++ finihed [INFO ] 2010-05-21 17:48:34,390 thread-0 start to b++ [INFO ] 2010-05-21 17:48:34,390 thread-0 b++ finished thread-0:a:1 [INFO ] 2010-05-21 17:48:34,421 thread-8 start to a++ [INFO ] 2010-05-21 17:48:34,421 thread-8 a++ finihed thread-0:b:1 [INFO ] 2010-05-21 17:48:34,515 thread-8 start to b++ [INFO ] 2010-05-21 17:48:34,515 thread-8 b++ finished thread-8:a:2 thread-8:b:2 [INFO ] 2010-05-21 17:48:34,546 thread-6 start to a++ [INFO ] 2010-05-21 17:48:34,546 thread-6 a++ finihed [INFO ] 2010-05-21 17:48:34,609 thread-6 start to b++ [INFO ] 2010-05-21 17:48:34,609 thread-6 b++ finished thread-6:a:3 thread-6:b:3 [INFO ] 2010-05-21 17:48:34,703 thread-4 start to a++ [INFO ] 2010-05-21 17:48:34,703 thread-4 a++ finihed [INFO ] 2010-05-21 17:48:34,765 thread-4 start to b++ [INFO ] 2010-05-21 17:48:34,765 thread-4 b++ finished thread-4:a:4 thread-4:b:4 [INFO ] 2010-05-21 17:48:34,859 thread-2 start to a++ [INFO ] 2010-05-21 17:48:34,859 thread-2 a++ finihed [INFO ] 2010-05-21 17:48:34,937 thread-2 start to b++ [INFO ] 2010-05-21 17:48:34,937 thread-2 b++ finished thread-2:a:5 thread-2:b:5 [INFO ] 2010-05-21 17:48:35,031 thread-9 start to a++ [INFO ] 2010-05-21 17:48:35,031 thread-9 a++ finihed [INFO ] 2010-05-21 17:48:35,109 thread-9 start to b++ [INFO ] 2010-05-21 17:48:35,109 thread-9 b++ finished
| 事实上"被打断",很大程度上是因为doWrite()里加了sleep/interrupted语句 如果没有加sleep/interrupted语句,doWrite就很难被print()打断,因为print()在run()方法里是在doWrite()之后执行的。 而doWrite()因为synchronized,实际上被阻塞住了,等于别的线程都阻塞在doWrite(),自然也不执行后边的print() 当然这样一来效率就很低了,同步方法效率都会很低, 因为它阻塞的是别的线程对方法的调用,通常采用的都是同步代码块.
如果想让各个方法都不被其他线程的"同名"方法打断,就每个方法都加synchronized
public synchronized void doWrite() { log.info("start to a++"); a++; log.info("a++ finihed");
log.info("start to b++"); b++; log.info("b++ finished");
}
public synchronized void print() { System.out.println("" + Thread.currentThread().getName() + ":a:" + a); System.out.println("" + Thread.currentThread().getName() + ":b:" + b); }
public void run() { for (int i = 0; i < 10; i++) { doWrite(); print(); }
|
1。每个方法都不会被其他线程的"同名"方法打断 2。但每个方法可能被其他线程的"非同名"方法打断
[INFO ] 2010-05-21 18:22:27,718 thread-0 start to a++ [INFO ] 2010-05-21 18:22:27,718 thread-0 a++ finihed [INFO ] 2010-05-21 18:22:27,718 thread-0 start to b++ [INFO ] 2010-05-21 18:22:27,718 thread-0 b++ finished [INFO ] 2010-05-21 18:22:27,718 thread-7 start to a++ [INFO ] 2010-05-21 18:22:27,718 thread-7 a++ finihed [INFO ] 2010-05-21 18:22:27,718 thread-7 start to b++ [INFO ] 2010-05-21 18:22:27,718 thread-7 b++ finished [INFO ] 2010-05-21 18:22:27,718 thread-9 start to a++ [INFO ] 2010-05-21 18:22:27,718 thread-9 a++ finihed [INFO ] 2010-05-21 18:22:27,718 thread-9 start to b++ [INFO ] 2010-05-21 18:22:27,718 thread-9 b++ finished thread-9:a:3 thread-9:b:3 [INFO ] 2010-05-21 18:22:27,718 thread-9 start to a++ [INFO ] 2010-05-21 18:22:27,718 thread-9 a++ finihed [INFO ] 2010-05-21 18:22:27,718 thread-9 start to b++ [INFO ] 2010-05-21 18:22:27,718 thread-9 b++ finished thread-9:a:4 thread-9:b:4 [INFO ] 2010-05-21 18:22:27,718 thread-9 start to a++ [INFO ] 2010-05-21 18:22:27,718 thread-9 a++ finihed [INFO ] 2010-05-21 18:22:27,718 thread-9 start to b++ [INFO ] 2010-05-21 18:22:27,718 thread-9 b++ finished
|
- 极端的"不被打断" ----连"被其他线程非同名方法打断"的情况都禁止掉
在run方法上也加synchronized
public synchronized void run() { for (int i = 0; i < 10; i++) { doWrite(); print(); } }
|
这样其实已经不是”并发“了,只有一个线程run方法全部执行完,其他线程run()才开始执行,实际上成了”顺序“执行 [INFO ] 2010-05-21 18:26:10,906 thread-0 start to a++ [INFO ] 2010-05-21 18:26:10,906 thread-0 a++ finihed [INFO ] 2010-05-21 18:26:10,906 thread-0 start to b++ [INFO ] 2010-05-21 18:26:10,906 thread-0 b++ finished thread-0:a:1 thread-0:b:1 [INFO ] 2010-05-21 18:26:10,906 thread-0 start to a++ [INFO ] 2010-05-21 18:26:10,906 thread-0 a++ finihed [INFO ] 2010-05-21 18:26:10,921 thread-0 start to b++ [INFO ] 2010-05-21 18:26:10,921 thread-0 b++ finished thread-0:a:2 thread-0:b:2 [INFO ] 2010-05-21 18:26:10,921 thread-0 start to a++ [INFO ] 2010-05-21 18:26:10,921 thread-0 a++ finihed [INFO ] 2010-05-21 18:26:10,921 thread-0 start to b++ [INFO ] 2010-05-21 18:26:10,921 thread-0 b++ finished thread-0:a:3 thread-0:b:3 [INFO ] 2010-05-21 18:26:10,921 thread-0 start to a++ [INFO ] 2010-05-21 18:26:10,921 thread-0 a++ finihed [INFO ] 2010-05-21 18:26:10,921 thread-0 start to b++ [INFO ] 2010-05-21 18:26:10,921 thread-0 b++ finished thread-0:a:4 thread-0:b:4 [INFO ] 2010-05-21 18:26:10,921 thread-0 start to a++ [INFO ] 2010-05-21 18:26:10,921 thread-0 a++ finihed [INFO ] 2010-05-21 18:26:10,921 thread-0 start to b++ [INFO ] 2010-05-21 18:26:10,921 thread-0 b++ finished thread-0:a:5 thread-0:b:5 [INFO ] 2010-05-21 18:26:10,921 thread-0 start to a++ [INFO ] 2010-05-21 18:26:10,921 thread-0 a++ finihed [INFO ] 2010-05-21 18:26:10,921 thread-0 start to b++ [INFO ] 2010-05-21 18:26:10,921 thread-0 b++ finished thread-0:a:6 thread-0:b:6
|
- join()方法——————让线程真正按启动顺序执行,必须等start()的运行完成后才继续运行后面的语句, 也是一种"顺序"执行
例子: 假设线程MyThread的功能是打印0-99
public class Test { public static void main(String[] args) throws Exception{ MyThread mt = new MyThread(); mt.start(); System.out.println(101); } }
|
输出其实是: 101,0,...99
| 现在加入join()方法
public class Test { public static void main(String[] args) throws Exception{ MyThread mt = new MyThread(); mt.start(); mt.join(); System.out.println(101); } }
|
输出: 0,...99,101
|
|