这是本文档旧的修订版!
2016年5月12日东哥在微信读书APP上送给我一本书《JAVA多线程编程核心技术》,作者高洪岩。在接下来的7天内读完了,感觉这本书写的挺好,作者基本把所有的知识点都结合代码例子来讲解,容易被程序员接受。其实在读的过程当中,就想着要把这本书的知识点做个整理,用于备忘也用于更好的掌握多线程。可能在我尝试整理知识点的时候,某些我觉得比较不常用的,我会比较简单的整理。
比如WINDOWS任务管理器里,看到的QQ.EXE,就是一个进程
比如QQ中的视频,发送文件,发送文字图片等,都是独立在运作的“线程”
多线程或者说多任务操作系统,可以最大限度地利用CPU的空闲时间在不同的任务之间不停的切换,由于切换的速度非常快,使使用者感觉多个任务是在同时进行的。当然后来也出现多个CPU,或者一个CPU多核就是为了加快机器运算。
package com.gxx.threads.study.test1; /** * 测试类-打印主线程的名字 * @author Gxx */ public class Test { /** * main方法 * @param args */ public static void main(String[] args) { /** * 打印main方法当前线程名字 * 输出:main */ System.out.println(Thread.currentThread().getName()); } }
输出
main
package com.gxx.threads.study.test2; /** * 继承Thread实现线程类 * @author Gxx */ public class MyThread1 extends Thread { /** * 覆盖Thread中的run方法 */ @Override public void run() { System.out.println("MyThread1.run()"); } }
package com.gxx.threads.study.test2; /** * 实现Runnable实现线程类 * @author Gxx */ public class MyThread2 implements Runnable { /** * 实现Runnable中的run方法 */ @Override public void run() { System.out.println("MyThread2.run()"); } }
本质上并没有什么区别,但是由于JAVA只支持单继承,如果继承了Thread就不能继承其它的父类了,所以绝大多数情况下是由于这个,而Thread类其实也实现了Runnable接口。
start()通过“线程规划器”此线程已经准备就绪,等待调用run(),CPU在不确定的时间调用run()
直接执行run,就不是“线程规划器”来调度了,而是执行run()的当前线程直接调用方法,如果是main()中调用,则当前线程就是main
多次start()会抛出异常java.lang.IllegalThreadStateException,报线程状态异常
package com.gxx.threads.study.test3; /** * 自定义线程类 * @author Gxx */ public class MyThread extends Thread { /** * 构造方法 */ public MyThread(){ System.out.println("线程[" + Thread.currentThread().getName() + "]执行构造方法"); } /** * 覆盖run方法 */ @Override public void run() { System.out.println("线程[" + Thread.currentThread().getName() + "]执行run"); } }
package com.gxx.threads.study.test3; /** * 测试类-测试start和run和多次start * @author Gxx */ public class Test { /** * main方法 * @param args */ public static void main(String[] args) { MyThread thread = new MyThread(); thread.setName("线程A");//设置线程名字 thread.run(); thread.start(); thread.start(); } }
输出
线程[main]执行构造方法 线程[main]执行run 线程[线程A]执行run Exception in thread "main" java.lang.IllegalThreadStateException at java.lang.Thread.start(Thread.java:705) at com.gxx.threads.study.test3.Test.main(Test.java:17)
package com.gxx.threads.study.test4; /** * 自定义线程类 * @author Gxx */ public class MyThread extends Thread { /** * 计数 */ int count = 10; /** * 覆盖run方法 */ @Override public void run() { System.out.println("线程[" + Thread.currentThread().getName() + "]执行count=" + (count--)); } }
package com.gxx.threads.study.test4; /** * 测试类-不共享变量,线程安全 * @author Gxx */ public class TestSafe { /** * main方法 * @param args */ public static void main(String[] args) { MyThread thead1 = new MyThread(); MyThread thead2 = new MyThread(); MyThread thead3 = new MyThread(); MyThread thead4 = new MyThread(); MyThread thead5 = new MyThread(); MyThread thead6 = new MyThread(); MyThread thead7 = new MyThread(); MyThread thead8 = new MyThread(); MyThread thead9 = new MyThread(); MyThread thead10 = new MyThread(); thead1.start(); thead2.start(); thead3.start(); thead4.start(); thead5.start(); thead6.start(); thead7.start(); thead8.start(); thead9.start(); thead10.start(); } }
输出
线程[Thread-0]执行count=10 线程[Thread-2]执行count=10 线程[Thread-1]执行count=10 线程[Thread-3]执行count=10 线程[Thread-4]执行count=10 线程[Thread-5]执行count=10 线程[Thread-6]执行count=10 线程[Thread-7]执行count=10 线程[Thread-8]执行count=10 线程[Thread-9]执行count=10
package com.gxx.threads.study.test4; /** * 测试类-共享变量,线程不安全 * @author Gxx */ public class TestNotSafe { /** * main方法 * @param args */ public static void main(String[] args) { MyThread thread = new MyThread(); Thread thead1 = new Thread(thread); Thread thead2 = new Thread(thread); Thread thead3 = new Thread(thread); Thread thead4 = new Thread(thread); Thread thead5 = new Thread(thread); Thread thead6 = new Thread(thread); Thread thead7 = new Thread(thread); Thread thead8 = new Thread(thread); Thread thead9 = new Thread(thread); Thread thead10 = new Thread(thread); thead1.start(); thead2.start(); thead3.start(); thead4.start(); thead5.start(); thead6.start(); thead7.start(); thead8.start(); thead9.start(); thead10.start(); } }
输出
线程[Thread-2]执行count=10 线程[Thread-3]执行count=9 线程[Thread-1]执行count=10 线程[Thread-4]执行count=8 线程[Thread-5]执行count=7 线程[Thread-6]执行count=6 线程[Thread-7]执行count=5 线程[Thread-8]执行count=4 线程[Thread-9]执行count=3 线程[Thread-10]执行count=2
package com.gxx.threads.study.test5; /** * 工具类 * @author Gxx */ public class Tools { /** * 计数 */ int count = 10; /** * 打印count * @throws Exception */ public synchronized void printCount() { try { count--; /** * 睡眠1秒 */ Thread.sleep(1000); System.out.println("线程[" + Thread.currentThread().getName() + "]执行count=" + count); } catch (InterruptedException e) { e.printStackTrace(); } } }
package com.gxx.threads.study.test5; /** * 自定义线程类 * @author Gxx */ public class MyThread extends Thread { /** * 工具类 */ Tools tools; /** * 构造方法 * @param tools */ public MyThread(Tools tools){ this.tools = tools; } /** * 覆盖父类的run方法 */ @Override public void run() { tools.printCount(); } }
package com.gxx.threads.study.test5; /** * 测试类-共享变量,使用synchronized使得线程安全 * @author Gxx */ public class Test { /** * main方法 * @param args */ public static void main(String[] args) { Tools tools = new Tools(); /** * 共用同一个tools */ MyThread thread1 = new MyThread(tools); MyThread thread2 = new MyThread(tools); thread1.start(); thread2.start(); } }
输出
线程[Thread-0]执行count=9 线程[Thread-1]执行count=8
注意:
public void println(String x) { synchronized (this) { print(x); newLine(); } }
package com.gxx.threads.study.test6; /** * 自定义线程类 * @author Gxx */ public class MyThread extends Thread { /** * 覆盖run方法 */ @Override public void run() { System.out.println("线程 run 开始 时间=" + System.currentTimeMillis()); System.out.println("线程 getId()=" + this.getId()); System.out.println("线程 run 中 isAlive()=" + this.isAlive()); System.out.println("线程 run 结束 时间=" + System.currentTimeMillis()); } }
package com.gxx.threads.study.test6; /** * 测试类-测试getId()、isAlive()和sleep() * @author Gxx */ public class Test { /** * main方法 * @param args */ public static void main(String[] args) { System.out.println("main主线程 开始 时间=" + System.currentTimeMillis()); System.out.println("main主线程 getId()=" + Thread.currentThread().getId()); MyThread thread = new MyThread(); System.out.println("线程 start前 isAlive()=" + thread.isAlive()); thread.start(); System.out.println("线程 start后 isAlive()=" + thread.isAlive()); System.out.println("main主线程 结束 时间=" + System.currentTimeMillis()); try { Thread.sleep(1000); System.out.println("main主线程 sleep(1秒)后 线程 isAlive=" + thread.isAlive()); } catch (InterruptedException e) { e.printStackTrace(); } } }
输出
main主线程 开始 时间=1464492826078 main主线程 getId()=1 线程 start前 isAlive()=false 线程 start后 isAlive()=true main主线程 结束 时间=1464492826080 线程 run 开始 时间=1464492826080 线程 getId()=8 线程 run 中 isAlive()=true 线程 run 结束 时间=1464492826080 main主线程 sleep(1秒)后 线程 isAlive=false
给线程打个中断的标记,线程继续运行
判断线程是否有中断的标记,如果有返回true,多次调用都返回true
静态方法,Thread.interrupted(),判断当前线程是否有中断的标记,如果有返回true,并清空该标记,下次再执行,则返回false
package com.gxx.threads.study.test7; /** * 自定义线程类 * @author Gxx */ public class MyThread extends Thread { /** * 覆盖run方法 */ @Override public void run() { System.out.println("run 开始"); this.interrupt(); System.out.println("执行this.interrupt()只是打个线程中断标记,线程还是继续往下走"); System.out.println("this.isInterrupted()=" + this.isInterrupted()); System.out.println("this.isInterrupted()=" + this.isInterrupted()); System.out.println("执行静态方法Thread.interrupted()=" + Thread.interrupted() + "后清空中断状态"); System.out.println("再执行静态方法Thread.interrupted()=" + Thread.interrupted()); System.out.println("this.isInterrupted()=" + this.isInterrupted()); System.out.println("run 结束"); } }
package com.gxx.threads.study.test7; /** * 测试类-测试interrupt、isInterrupted、interrupted * @author Gxx */ public class Test { /** * main方法 * @param args */ public static void main(String[] args) { System.out.println("main 开始"); MyThread thread = new MyThread(); thread.start(); System.out.println("main 结束"); } }
输出
main 开始 main 结束 run 开始 执行this.interrupt()只是打个线程中断标记,线程还是继续往下走 this.isInterrupted()=true this.isInterrupted()=true 执行静态方法Thread.interrupted()=true后清空中断状态 再执行静态方法Thread.interrupted()=false this.isInterrupted()=false run 结束
package com.gxx.threads.study.test8; /** * 自定义线程类 * @author Gxx */ public class MyThread extends Thread { /** * 覆盖run方法 */ @Override public void run() { System.out.println("run 开始"); System.out.println("run 准备执行sleep(1000) 睡眠1秒"); try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("run 结束"); } }
package com.gxx.threads.study.test8; /** * 测试类-测试线程interrupt()然后sleep() * @author Gxx */ public class Test { /** * main方法 * @param args */ public static void main(String[] args) { System.out.println("main 开始"); MyThread thread = new MyThread(); thread.start(); thread.interrupt(); System.out.println("main 执行thread.interrupt(),给thread打个中断标记"); System.out.println("main 结束"); } }
输出
main 开始 main 执行thread.interrupt(),给thread打个中断标记 main 结束 run 开始 run 准备执行sleep(1000) 睡眠1秒 run 结束 java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.gxx.threads.study.test8.MyThread.run(MyThread.java:16)
package com.gxx.threads.study.test9; /** * 自定义线程类 * @author Gxx */ public class MyThread extends Thread { /** * 覆盖run方法 */ @Override public void run() { System.out.println("run 开始"); System.out.println("run 准备执行sleep(10000) 睡眠10秒"); try { sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("run 结束"); } }
package com.gxx.threads.study.test9; /** * 测试类-测试线程sleep()然后interrupt() * @author Gxx */ public class Test { /** * main方法 * @param args */ public static void main(String[] args) { System.out.println("main 开始"); MyThread thread = new MyThread(); thread.start(); System.out.println("main 睡眠1秒"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("main 执行thread.interrupt(),给thread打个中断标记"); thread.interrupt(); System.out.println("main 结束"); } }
输出
main 开始 main 睡眠1秒 run 开始 run 准备执行sleep(10000) 睡眠10秒 main 执行thread.interrupt(),给thread打个中断标记 main 结束 run 结束 java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.gxx.threads.study.test9.MyThread.run(MyThread.java:16)