第二十七节(多线程、线程的创建和启动、生命周期、调度、控制、同步)
线程指进程中的一个执行场景,也就是执行流程,那么进程和线程的区别是什么 1. 每个进程是一个应用程序,都有独立的内存空间 2. 同一个进程中的线程共享其进程中的内存和资源 (共享的内存是堆内存和方法区内存,栈内存不共享,每个线程有自己的) 什么是进程? 一个进程对应一个应用程序。 例如:在 windows 操作系统启动 Word 就表示启动了一个进程。在 java 的开发环境下启动 JVM, 就表示启动了一个进程。现代的计算机都是支持多进程的,在同一个操作系统中,可以同时启动多个进程。
/* 分析一下程序有几个线程 只有一个线程,就是主线程 main,m1,m2,m3 这四个方法在同一个栈空间中 没有启动其他任何线程 */ public class ThreadTest01{ public static void main(String[] args){ ming01(); } public static void arry01(){ ming2(); } public static void arry02(){ ming03(); } public static void arry03(){ System.out.println("电子科技大学中山学院"); } }
/* 在Java语言中实现多线程第一种方式: 1. 继承java.lang.Thread 2. 重写run方法 三个知识点: 定义线程 创建线程 启动线程 */ public class ThreadTest02{ public static void main(String[] args){ // 创建一个线程 Thread t = new Student(); // 启动线程 t.start(); // start方法执行完瞬间结束,告诉JVM再分配一个新的线程 给t线程 // run 不需要手动调用的,系统线程启动之后会自动调用run方法 // 是随机分配的,没有规律 // t.run(); 这是普通方法的调用,这样做程序只有一个线程,run方法结束之后,下边的程序才能继续运行 for(int i = 0; i < 5; i++){ System.out.println("main---------: "+i); } /* 有了多线程之后,main方法结束只是主线程中没有方法栈帧了 但是其他线程或者其他栈中还有栈帧 main方法结束,程序可能还在运行 */ } } class Student extends Thread{ // 重写run方法 public void run(){ for(int i = 0; i < 10; i++){ System.out.println("run: " + i); } } }
/* Java中实现多线程的第二种方法: 1. 写一个类实现 2. 实现run方法 */ public class ThreadTest03{ public static void main(String[] args){ // 创建线程 Thread t = new Thread(new Teacher()); // 启动 t.start(); } } // 这种方法是推荐的,因为一个类实现接口之外保留了 类的继承 class Teacher implements Runnable { // 重写run方法 public void run(){ for(int i = 0; i < 10; i++){ System.out.println("run: " + i); } } }
/* 掌握线程方法: 1. 获取当前线程的对象 currentThread 2. 给线程起名 t.setName("名称"); 3. 获取线程的名字:t.getName(); */ public class ThreadTest04{ public static void main(String[] args){ // 获取当前线程对象 main 主线程 Thread t = Thread.currentThread(); // 获取线程的名称 System.out.println("线程的名称:"+t.getName());//输出main Thread t1 = new Thread(new MingTest()); // 给线程起名 t1.setName("Ming"); t1.start(); Thread t2 = new Thread(new MingTest()); // 给线程重命名 t2.setName("中山学院"); t2.start(); } } class MingTest implements Runnable{ public void run(){ Thread t = Thread.currentThread(); System.out.println("线程名称:"+t.getName()); } }
/* 线程优先级的高的获取cpu的时间片 相对多一些 最高:10 最低:1 默认:5 优先级:1 - 10 优先级高的线程 会得到CPU的时间多一些,优先执行完成 */ public class ThreadTest05{ public static void main(String[] args){ System.out.println("最高:" + Thread.MAX_PRIORITY); System.out.println("最小:" + Thread.MIN_PRIORITY); System.out.println("默认:" + Thread.NORM_PRIORITY); Thread t1 = new Keke(); t1.setName("t1"); Thread t2 = new Keke(); t2.setName("t2"); // 都是 5 System.out.println("t1优先级:" + t1.getPriority()); System.out.println("t2优先级:" + t2.getPriority()); // 设置优先级 t1.setPriority(6); t2.setPriority(3); // 启动 t1.start(); t2.start(); } } class Keke extends Thread{ public void run(){ for(int i = 0 ; i < 5; i++){ System.out.println(Thread.currentThread().getName() + "----------- : " + i); } } }
/* Thread.sleep(); 让当前正在执行的线程休眠(暂停执行) sleep 方法是一个静态方法 该方法的作用:阻塞当前线程,腾出CPU,让给其他线程 */ public class ThreadTest06{ public static void main(String[] args){ Thread t1 = new Ming(); t1.setName("t1"); t1.start(); // 获取当前线程对象 main 主线程 Thread t = Thread.currentThread(); // 获取线程的名称 System.out.println("线程的名称:"+t.getName());//输出main // 阻塞主线程 for(int i = 0; i < 20; i++){ System.out.println(Thread.currentThread().getName() + "----------- : " + i); try{ Thread.sleep(1000); } catch(InterruptedException e){ e.printStackTrace(); } } } } class Ming extends Thread{ public void run(){ System.out.println("线程正在启动中......."); for(int i = 0; i < 20; i++){ System.out.println(Thread.currentThread().getName() + "----------- : " + i); try{ Thread.sleep(2000); // 让当前程序阻塞2S } catch(InterruptedException e){ e.printStackTrace(); } } } } //输出main跟ti是随机的
/* Thread.yield(); 暂停当前正在执行的线程对象,并执行其他线程。 1. 该方法是一个静态方法 2. 作用: 给同一个优先级的线程让位,但是让位时间不固定 3. 和sleep方法相同,就是yield时间不固定 他与sleep类似,只是不能由用户指定暂停多长时间,并且yield()只能让 同优先级的线程有执行的机会 */ public class ThreadTest08{ public static void main(String[] args){ // 创建线程 Thread t = new Ming5(); t.setName("t"); // 启动线程 t.start(); // 主线程 for(int i = 0; i < 20; i++){ System.out.println(Thread.currentThread().getName()+"------- "+i); } System.out.println("Ming帅了 !"); } } class Ming5 extends Thread{ public void run(){ for(int i = 0; i < 10; i++){ System.out.println(Thread.currentThread().getName()+"------- "+i); if(i % 2 == 0){ Thread.yield(); } } } }
/* 线程的合并 */ public class ThreadTest09{ public static void main(String[] args){ Thread t = new Thread(new Arry6()); t.setName("t"); t.start(); try{ // 合并线程 t.join(); // t 和 主线程合并,单线程的程序 } catch(InterruptedException e){ e.printStackTrace(); } System.out.println("---------main end--------"); // 主线程 for(int i = 0; i < 10; i++){ System.out.println(Thread.currentThread().getName()+"------- "+i); } // 当前线程可以调用第一个线程的join方法,调用后当前线程会被阻塞不再执行, // 直到被调用的线程执行完毕,当前线程才会执行 } } class Arry6 implements Runnable{ public void run(){ for(int i = 0; i < 10; i++){ try{ Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+"------- "+i); }catch(InterruptedException e){ e.printStackTrace(); } } } }