java基础 day16---多线程

    科技2022-07-10  164

    1.什么是进程 概念:正在运行的程序,是系统进行资源分配的基本单位。 目前的操作系统都是支持多进程的,可以同时执行多个进程,通过进程ID区分 2.什么是线程 概念:线程,又称轻量级进程,是进程中的一条执行路径,也是CPU的基本调度单位。 一个进程由一个或多个线程组成,彼此间完成不同的工作,同时执行,称为多线程。 宏观上是并行执行,微观上是串行的(电脑是单核的,微观上是串行的;如果电脑是多核的,其实真正实现了并行执行)。

    3.进程和线程的区别

    进程是操作系统资源分配的基本单位,而线程是CPU的基本调度单位一个程序运行后至少包含一个进程一个进程可以包含多个线程,但是至少需要有一个线程,否则这个进程就没有意义。进程之间不能共享数据段地址,但同进程的线程之间可以

    4.线程的组成

    CPU时间片:操作系统 OS会为每个线程分配执行时间运行数据:(1)堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象 (2)栈空间:存储线程需使用的局部变量,每个线程都拥有独立的栈线程的逻辑代码

    5.线程的特点

    线程抢占式执行(效率高;可防止单一线程长时间独占CPU)在单核CPU中,宏观上同时执行,微观上顺序执行

    6、创建线程

    继承Thread类 //创建线程的第一种方式:继承Thread类 public class MyThread extends Thread{ //1.继承Thread类 //2.重写run方法 @Override public void run() { for(int i=0;i<100;i++) { //this.getId()获取线程的id this.getName()获取线程的名字(只能在继承Thread类下才可以用) System.out.println("线程id:"+this.getId()+"线程名称:"+this.getName()+"子线程-------"+i); //或者用下面这行代码也是一样的(不继承Thread类也可以用)【建议用这种方式,因为不继承Thread类也可以用】 //System.out.println("线程id:"+Thread.currentThread().getId()+"线程名称:"+Thread.currentThread().getName()); } } } public static void main(String[] args) { //3.创建对象 MyThread myThread=new MyThread(); //修改线程名称 myThread.setName("我的子线程1"); //4.调用start()方法,启动线程 myThread.start(); MyThread myThread2=new MyThread(); myThread2.start(); for(int i=0;i<100;i++) { System.out.println("主线程---"+i); } /** *抢占式执行,每一次运行结果都不一样 */ }

    步骤总结:

    (1)继承Thread类 (2) 重写run方法 (3)在main方法中创建对象 (4)调用start()方法,启动线程 实现Runnable接口 /** * 创建线程的第二种方式:实现Runnable接口 * @author 1 * */ public class MyRunnable implements Runnable{ //1.实现Runnable接口 //2.重写run方法 @Override public void run() { for(int i=0;i<10;i++) { //这里就不能使用this.getId(),因为没有继承Thread类 System.out.println("线程id:"+Thread.currentThread().getId()+"线程名称:"+Thread.currentThread().getName()+".........."+i); } } } public static void main(String[] args) { //3.创建Runnable对象 MyRunnable mr=new MyRunnable(); //4.创建线程对象 Thread thread=new Thread(mr, "我的子线程1"); //5.调用start() thread.start(); for(int i=0;i<100;i++) { System.out.println("main"+"---------------"+i); } } //优化代码(使用了匿名内部类) Runnable runnable=new Runnable() { public void run() { for(int i=0;i<10;i++) { //这里就不能使用this.getId(),因为没有继承Thread类 System.out.println("线程id:"+Thread.currentThread().getId()+"线程名称:"+Thread.currentThread().getName()+".........."+i); } } }; //创建线程对象 Thread thread=new Thread(runnable, "我的子线程"); //启动线程 thread.start();

    7.线程的基本状态

    初始状态:线程对象被创建,即为初始状态,只在堆中开辟内存,与常规对象无异就绪状态:调用start方法之后,进入就绪状态。等到OS选中,并分配时间片运行状态:获得时间片之后,进入运行状态,如果时间片到期,则回到就绪状态终止状态:主线程main()或独立线程run()结束,进入终止状态,并释放持有的时间片

    8.线程的常见方法

    休眠:(当前线程主动休眠xx毫秒)

    Thread.sleep();//参数的单位是毫秒

    放弃:(当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片) Thread.yield();

    加入:(允许其他线程加入到当前线程中,并阻塞当前线程,直到加入的线程执行完毕,当前线程才会继续执行)

    对象.join();

    优先级(线程优先级为1-10,默认为5,优先级越高,表示获取CPU机会越多) 线程对象.setPriority();

    9.同步方式

    同步代码块: synchronized (this) {//共享资源必须是引用类型 if(ticket<=0) { break; } System.out.println(Thread.currentThread().getName()+"....还剩"+ticket+"张票"); ticket--; }

    案例:

    package com.hp.runnable; /** * 实现4个窗口共卖100张票 * @author 15163095307 * */ public class SellTickets { public static void main(String[] args) { //1.创建Runnable对象 Runnable runnable=new Runnable() { private int ticket=100; // Object obj=new Object(); @Override public void run() { while(true) { synchronized (this) {//共享资源必须是引用类型 if(ticket<=0) { break; } System.out.println(Thread.currentThread().getName()+"....还剩"+ticket+"张票"); ticket--; } } } }; //2.创建线程对象 Thread thread=new Thread(runnable,"窗口1"); Thread thread1=new Thread(runnable,"窗口2"); Thread thread2=new Thread(runnable,"窗口3"); Thread thread3=new Thread(runnable,"窗口4"); //3.启动线程 thread.start(); thread1.start(); thread2.start(); thread3.start(); } } 同步方法 在方法返回值类型前面加上synchornized public synchornized boolean sale(){ if(ticket<=0) { break; } System.out.println(Thread.currentThread().getName()+"....还剩"+ticket+"张票"); ticket--; }

    案例:

    package com.hp.runnable; public class Sale { /** * 实现4个窗口共卖100张票 * @author 15163095307 * */ private static int ticket=100; public static void main(String[] args) { //1.创建Runnable对象 Runnable runnable=new Runnable() { // Object obj=new Object(); @Override public void run() { while(true) { if(!sale()) { break; } } } }; //2.创建线程对象 Thread thread=new Thread(runnable,"窗口1"); Thread thread1=new Thread(runnable,"窗口2"); Thread thread2=new Thread(runnable,"窗口3"); Thread thread3=new Thread(runnable,"窗口4"); //3.启动线程 thread.start(); thread1.start(); thread2.start(); thread3.start(); } public synchronized static boolean sale() { if(ticket<=0) { return false; } System.out.println(Thread.currentThread().getName()+"....还剩"+ticket+"张票"); ticket--; return true; } }

    10.线程池 为什么会有线程池的概念呢? 线程是宝贵的内存资源,单个线程约占1MB的空间,过多分配易造成内存溢出; 频繁的创建以及销毁线程会增加虚拟机回收频率,资源开销,造成程序性能的下降。

    线程池:线程容器,可设定线程分配的数量上限;将预先创建的线程对象存入池中,并重用线程池中的线程对象;避免频繁的创建和销毁线程池的原理:将任务交给线程池,由线程池分配线程,运行任务,并在当前任务结束后复用线程(比如一个线程池中有三个预先创建的线程,外边有4个任务执行,那么此时会随机选择三个任务,三个线程对象分别执行任务,剩下的那个任务等待,直到某个线程执行完某个任务,那么等待的任务再被执行,这就实现了线程的复用) package com.hp.xianchengchi; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 演示线程池的创建 * Executor:线程池的根接口,execute() * * ExecutorService:包含了管理线程池的一些方法,比如submit shutdown * * Executors:创建线程池的工具类 * (1)创建固定线程个数线程池 * (2)创建缓存线程池,由任务的多少来决定,个数不固定 * (3)创建单线程池 * (4)创建调度线程池 调度:周期,定时执行 * @author 1 * */ public class Demo1 { public static void main(String[] args) { //1.创建固定线程个数线程池 // ExecutorService es = Executors.newFixedThreadPool(4); //1.1创建缓冲线程池,线程个数是由任务的个数来决定的 ExecutorService es= Executors.newCachedThreadPool(); //2.创建任务 Runnable runnable=new Runnable() { private int tickets=100; @Override public void run() { while(true) { if(tickets<=0) { break; } System.out.println(Thread.currentThread().getName()+"卖了"+tickets+"票"); tickets--; } } }; for(int i=1;i<=4;i++) { //3.提交任务 es.submit(runnable); } //4.关闭线程池 es.shutdown();//等待所有任务执行完毕,然后关闭线程池 } }
    Processed: 0.019, SQL: 11