线程回顾
1.程序、进程、线程
程序: Program,是一个指令的集合
进程: Process,(正在执行中的程序)是一个静态的概念,进程是程序的一次静态执行过程, 占用特定的地址空间.
每个进程都是独立的,由 3 部分组成 cpu,data,code
缺点:内存的浪费,cpu 的负担
线程: 是进程中一个“单一的连续控制流程”,线程又被称为轻量级进程,一个进程可拥有多个并行的(concurrent)线程 一个进程中的线程共享相同的内存单元/内存地址空间(指共享进程空间) 由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这就使得通信更简便而且信息传递的速度也更快。
2.在 Java 中创建线程的两种方式
1) 继承 Thread
2) 实现 Runnable 接口
3 线程的生命周期
4 同步与死锁
1) 同步方法 同步监视器为当前对象 this
2) 同步代码块(同步监视器/共享资源的对象){
}
过多的同步就会导致死锁
5.线程间的通信
1) wait() 等待
2) notify() 唤醒
3) notifyAll()
需要与同步一起使用
6.案例
编写两个线程,一个线程打印 1-52 的整数,另一个线程打印字母 A-Z。打印顺序为 12A34B56C….5152Z。即按照整数和
字母的顺序从小到大打印,并且每打印两个整数后,打印一个字母,交替循环打印,直到打印到整数 52 和字母 Z 结束。
步骤:
1) 编写打印类 Printer,声明私有属性 index,初始值为 1,用来表示是第几次打印。
2) 在打印类 Printer 中编写打印数字的方法 print(int i),3 的倍数就使用 wait()方法等待,否则就输出 i,使用 notifyAll()进行唤醒其它线程。
3) 在打印类 Printer 中编写打印字母的方法 print(char c),不是 3 的倍数就等待,否则就打印输出字母 c,使用 notifyAll()进行唤醒其它线程。
1 public class Printer { 2 3 private int index = 1;//用于统计第几次打印 4 5 public synchronized void print(int number) { //打印数字 6 while(index%3 == 0) { //3的倍数则等待 7 try { 8 super.wait(); 9 } catch (InterruptedException e) { 10 // TODO 自动生成的 catch 块 11 e.printStackTrace(); 12 } 13 } 14 System.out.print(number); 15 index++; 16 super.notifyAll();//唤醒在Printer这个对象上的所有的等待的线程 17 18 } 19 20 public synchronized void print(char c) { 21 while(index%3 != 0) { //不是3的倍数则等待 22 try { 23 super.wait(); 24 } catch (InterruptedException e) { 25 // TODO 自动生成的 catch 块 26 e.printStackTrace(); 27 } 28 } 29 System.out.print(c); 30 index++; 31 super.notifyAll();//唤醒在Printer这个对象上的所有的等待的线程 32 33 } 34 }
4) 编写打印数字的线程 NumberPrinter 继承 Thread 类,声明私有属性 private Printer p;在构造方法中进行赋值,实现父类的 run 方法,调用 Printer 类中的输出数字的方法。
1 public class NumberPrinter extends Thread{ //打印数字的线程 2 private Printer p; 3 4 5 public NumberPrinter(Printer p) { 6 super(); 7 this.p = p; 8 } 9 10 11 @Override 12 public void run() { 13 for(int i=1; i<=52; i++) { 14 p.print(i); 15 } 16 } 17 18 }
5) 编写打印字母的线程 LetterPrinter 继承 Thread 类,声明私有属性 private Printer p;在构造方法中进行赋值,实现父类的run 方法,调用 Printer 类中的输出字母的方法。
1 public class LeeterPrinter extends Thread{ 2 private Printer p; 3 4 public LeeterPrinter(Printer p) { 5 super(); 6 this.p = p; 7 } 8 9 @Override 10 public void run() { 11 for(char c='A'; c<='Z'; c++) { 12 p.print(c); 13 } 14 } 15 16 }
6) 编写测试类 Test,创建打印类对象,创建两个线程类对象,启动线程。
1 public class Test { //测试类 2 public static void main(String[] args) { 3 //1创建打印类对象 4 Printer p= new Printer(); 5 //2创建两个线程类对象 6 NumberPrinter pi = new NumberPrinter(p); 7 LeeterPrinter pc = new LeeterPrinter(p); 8 //3启动线程 9 pi.start(); 10 pc.start(); 11 } 12 }
运行结果
12A34B56C78D910E1112F1314G1516H1718I1920J2122K2324L2526M2728N2930O3132P3334Q3536R3738S3940T4142U4344V4546W4748X4950Y5152Z