Java是最早开始有并发的语言之一,再过去传统多任务的模式下,人们发现很难解决一些更为复杂的问题,这个时候我们就有了并发.
引用
多线程比多任务更加有挑战。多线程是在同一个程序内部并行执行,因此会对相同的内存空间进行并发读写操作。这可能是在单线程程序中从来不会遇到的问题。其中的一些错误也未必会在单CPU机器上出现,因为两个线程从来不会得到真正的并行执行。然而,更现代的计算机伴随着多核CPU的出现,也就意味着不同的线程能被不同的CPU核得到真正意义的并行执行。
那么,要开始Java并发之路,就要开始从java线程开始说起.
本篇幅将是本系列博客的开山篇,也就是基础线程的复习.
线程简介
线程百科
1. `线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。`
线程优点
资源利用率更好
程序设计在某些情况下更简单
程序响应更快
线程代价
设计更复杂
上下文切换的开销上升
增加资源消耗
线程的实现方式
线程我们有不同的实现方式,生产环境中用到的也有所不同,那么,我们先来通过Demo看一下每种实现方式的区别.
通过Thread 实现的线程
1. `public class Demo1 {` 2. `public static void main(String args[]) {` 3. `Thread thread = Thread.currentThread();` 4. `System.out.println("当前线程:" + thread);` 6. `thread.setName("hyh thread");//修改线程名称` 8. `System.out.println("修改名称之后:" + thread);` 10. `try {` 11. `for (int a = 5; a > 0; a--) {` 12. `System.out.println(a);` 14. `thread.sleep(1000);` 15. `}` 16. `} catch (Exception e) {` 17. `System.out.println("出现异常");` 18. `}` 19. `}`
通过集成Runnable接口实现
Demo2.class 清单:
1. `public class Demo2 implements Runnable {` 3. `Thread t;` 5. `//空构造函数` 6. `Demo2() {` 7. `t = new Thread(this, "测试线程");` 8. `System.out.println("子线程" + t);` 9. `t.start();` 10. `}` 12. `public void run() {` 13. `try {` 14. `for (int a = 5; a > 0; a--) {` 15. `System.out.println("子线程" + a);` 16. `Thread.sleep(1000);` 17. `}` 18. `} catch (InterruptedException e) {` 19. `System.out.println("异常");` 20. `}` 21. `System.out.println("退出子线程");` 22. `}` 23. `}` 25. `/**` 26. `* 主类` 27. `*/` 28. `class ThreadDemo {` 29. `public static void main(String args[]) {` 30. `new Demo2();//创建一个新线程` 31. `try {` 32. `for (int i = 5; i > 0; i--) {` 33. `System.out.println("主线程:" + i);` 34. `Thread.sleep(1000);` 35. `}` 36. `} catch (InterruptedException e) {` 37. `System.out.println("主线程异常");` 38. `}` 39. `//主线程退出` 40. `System.out.println("主线程退出");` 42. `}` 43. `}`
通过集成 Thread 重写run方法实现
1. `public class Demo3 extends Thread {` 2. `public Demo3() {` 3. `//创建新线程` 4. `super("线程Demo");` 5. `System.out.println("子线程:" + this);` 6. `start();` 7. `}` 9. `@Override` 10. `public void run() {` 11. `try {` 12. `for (int a = 5; a > 0; a--) {` 13. `System.out.println("子线程:" + a);` 14. `Thread.sleep(500);` 15. `}` 16. `} catch (InterruptedException e) {` 17. `System.out.println("子程序异常");` 18. `}` 19. `}` 21. `}` 23. `class MasterThread {` 24. `public static void main(String args[]) {` 25. `new Demo3();//创建新线程` 27. `try {` 28. `for (int i = 5; i > 0; i--) {` 29. `System.out.println("主线程:" + i);` 30. `Thread.sleep(1000);` 31. `}` 32. `} catch (InterruptedException e) {` 33. `System.out.println("主程序异常");` 34. `}` 35. `System.out.println("主程序退出...");` 36. `}` 37. `}`
三个线程的实现
在日常生产中,使用线程可以通过实现Runnable接口.下面我们通过该方法实现简单的三个线程Demo
结构: 创建一个Demo4类,另外一个主类MultThreadDemo.
清单:
1. `public class Demo4 implements Runnable {` 2. `//全局变量` 3. `String name;` 4. `Thread thread;` 6. `//构造器` 7. `public Demo4(String th) {` 8. `name = th;` 9. `thread = new Thread(this, name);` 10. `System.out.println("新线程" + thread);` 11. `//开始线程` 12. `thread.start();` 13. `}` 15. `//重写run方法` 16. `public void run() {` 17. `try {` 18. `for (int a = 5; a > 0; a--) {` 19. `System.out.println(name + ":" + a);` 20. `Thread.sleep(1000);` 21. `}` 22. `} catch (InterruptedException e) {` 23. `System.out.println("异常");` 24. `}` 25. `System.out.println(name + "线程结束");` 26. `}` 27. `}` 29. `/**` 30. `* 测试类` 31. `*` 32. `* @author hyh` 33. `*/` 34. `class MultThreadDemo {` 36. `public static void main(String[] args) {` 37. `//创建三个线程` 38. `Demo4 thread_1 = new Demo4("线程一");` 39. `Demo4 thread_2 = new Demo4("线程二");` 40. `Demo4 thread_3 = new Demo4("线程三");` 41. `//查看状态` 42. `System.out.println("线程一状态:" + thread_1.thread.isAlive());` 43. `System.out.println("线程二状态:" + thread_2.thread.isAlive());` 44. `System.out.println("线程三状态:" + thread_3.thread.isAlive());` 46. `try {` 47. `System.out.println("等待其他线程结束");` 48. `//使用join确保主线程最后运行` 49. `thread_1.thread.join();` 50. `thread_2.thread.join();` 51. `thread_3.thread.join();` 52. `} catch (InterruptedException e) {` 53. `System.out.println("线程异常");` 55. `}` 56. `//查看状态` 57. `System.out.println("线程一:" + thread_1.thread.isAlive());` 58. `System.out.println("线程二:" + thread_2.thread.isAlive());` 59. `System.out.println("线程三:" + thread_3.thread.isAlive());` 60. `}` 61. `}`
到此,开山Demo完成.
思考:进程与线程的比较
进程
资源分配的基本单位。
所有与该进程有关的资源,都被记录在进程控制块PCB中。
进程处理机的调度单位,拥有完整的虚拟地址空间。当进程发生调度时,不同的进程拥有不同的虚拟地址空间,而同一进程内的不同线程共享同一地址空间。
线程与资源分配无关,属于某一个进程,并与其他线程共享进程资源。
线程只由相关堆栈(系统栈或用户栈)寄存器和线程控制表TCB组成。寄存器可被用来存储线程内的局部变量,但不能存储其他线程的相关变量。
进程在多线程中,进程不是一个可执行的实体。
两者比较:
**调度和切换:**线程上下文切换比进程上下文切换要快得多。
**通信:**进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
**地址空间和其它资源(如打开文件):**进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
(本篇完)