Java 线程的一些基本知识

线程

1. 并发与并行

  • 并发:只两个或者多个事件在同一个时间段内发生
  • 并行:只两个或者多个事件在同一个时刻发生(同时发生)。

2.线程和进程

  • 进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。

  • 线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序

    简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程

3. 多线程实现的两种方式

多线程实现的两种方式:

  • ① 自定义一个线程类, extends Thread,重写 run 方法,创建自定义的线程对象,开启线程 start()。

  • ② 自定义一个任务类, implements Runnable,重写 run 方法,创建自定义的任务对象,通过任务对象, 构造一个线程对象,开启线程 start()。

或者以上两种方式的匿名内部类改写,均可实现多线程。

public class ThreadDemo01 {
    public static void main(String[] args) {
        //继承
        MyThread01 myThread01 = new MyThread01();
        myThread01.start();

        //接口实现类
        MyThread02 task = new MyThread02();
        Thread t = new Thread(task);
        t.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("main:" + i);
        }
    }
}

public class MyThread02 implements Runnable {

    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("接口多线程:" + i);
        }
    }
}

public class MyThread01 extends Thread {

    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("继承多线程:" + i);
        }
    }
}

注意:不是哪个线程先start, 就先执行哪个线程, 线程的执行顺序, 是不固定的

4. 线程常用方法

  线程Thread的构造方法:

	 1.new 自定义线程类(): 自定义类的构造方法, 随意
	 
	 2.new Thread(): 无参构造器
	 
	 3.new Thread(String): String->指定的线程名
	 
	 4.new Thread(Runnable): Runnable->线程任务
	 
	 5.new Thread(Runnable, String): Runnable->线程任务, String->指定的线程名

线程Thread常用API:

	 1.static Thread currentThread(): 获得当前正在执行的线程对象
	 
	 2.String getName(): 获得线程对象的名字, 线程在创建时可以指定名字, 也可以默认分配名字
	 
	 3.int getPriority(): 返回此线程的优先级
	   void setPriority(int): 设置线程的优先级
		   优先级: 1~10
		   改变CPU分配时间片的概率
	   
	 4.boolean isDaemon(): 测试这个线程是否是守护线程
	   void setDaemon(boolean): 设置这个线程是守护线程
		    守护线程 - 前台线程
		    当所有的前台线程结束, 守护线程也会自动结束
		    GC 就是守护线程
	   
	 5.static void sleep(long): 线程休眠指定时间
	   会有一个已检查异常, 所以必须要 try-catch
	   
	 6.void join(): 等待调用这个方法的线程结束, 再继续后续代码
	   会有一个已检查异常, 所以必须要 try-catch
	   
	 7.static void yield(): 主动放弃cpu的时间片

5. 线程同步

5.1 同步代码块

  同步代码块: synchronized 关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

  synchronized使用原则: 尽量将少的代码加锁,可以只将一部分代码加锁, 同步代码锁, 需要借助一个对象。

  加锁的对象: 可以是任意对象, 只需要确保多个同步的线程, 对象唯一就可以了。

  通常使用this对象。

   对象锁: 一个对象只能加一把锁, 并且只能同时被一个线程持有。

public void saleTicket() {
//        synchronized (this) {
        synchronized (object) {
            if (count == 0) {
                throw new RuntimeException("票卖完了!");
            }
            System.out.println(Thread.currentThread().getName() + "正在出票: " + count);
            count--;
        }

        System.out.println(Thread.currentThread().getName()+"卖完一张票");
    }
}

5.2 同步方法

  在方法上加锁, 称为同步方法锁。锁在方法上, 实际上就是在this对象上加锁

public synchronized void saleTicket() {
        if (count == 0) {
            throw new RuntimeException("票卖完了!");
        }
        System.out.println(Thread.currentThread().getName()+"正在出票: " + count);
        count--;

        System.out.println(Thread.currentThread().getName()+"卖完一张票");
    }

5.3 Lock锁

    实现类: ReentrantLock lock = new ReentrantLock();

      加锁: 锁对象.lock();
      解锁: 锁对象.unlock();

    private ReentrantLock lock = new ReentrantLock();

    public void saleTicket() {
        // 加上锁
        lock.lock();

        if (count == 0) {
            throw new RuntimeException("票卖完了!");
        }
        System.out.println(Thread.currentThread().getName() + "正在出票: " + count);
        count--;

        // 打开锁
        lock.unlock();

        System.out.println(Thread.currentThread().getName() + "卖完一张票");
    }

6. 线程状态

线程状态导致状态发生的条件
NEW(新建)线程刚被创建,但是未启动。还没有调用start方法。
Runnable(可运行)线程可以在java虚拟中的运行的状态,可能正在运行自己的代码,也可能没有,这取决于操作系统的处理器。
Block(锁阻塞)当一个线程视图获取一个对象锁。而该对象被其他的线程所持有,则该线程进入Block状态;当该线程持有锁时,该线程变成Runable状态。
Waiting(无限等待)一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个状态是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能唤醒。
Timed Waiting(计时等待)同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态将一直保持到超时期满或者接收到唤醒通知。带有超时参数的方法一样Thread.sleep、Object.wait。
Teminated(被终止)因为run方法正常退出而死亡,或者英文没有捕获的异常终止了run方法而死亡。

在这里插入图片描述
线程通信: 共享资源

    wait() 和 notify()
    
    notify() - 每次只能唤醒一个线程, 只能唤醒等待时间久的那个线程
    notifyAll() - 唤醒所有正在等待的线程
    wait() -> 只能被notify() 或者 notifyAll() 唤醒
    wait(long) -> 到时间以后, 自动醒来

7. 线程池

7.1 线程池的概念

    一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多的资源。

7.2 线程池的好处

  • ① 降低资源消耗,减少了创建和销毁线程的次数,每个工作线程都可以重复利用。

  • ② 提高响应速度,当任务到达时,任务可以不需要等创建线程就可以立即执行任务。

  • ③ 提高线程的可管理性,可以根据系统的承受能力,调整线程池中工作线程的数量,防止消耗过多的内存

7.3 线程池的工作原理

  • ① 线程池判断核心线程池里的线程是否都在执行任务,如果不是,则创建一个新的工作线程来执行任务,如果核心线程池里的线程都在执行任务,则进入下一个流程。

  • ② 线程池判断工作队列是否已满,没满,则将新提交的任务存储在这个工作队列里,满了,进入下一个流程。

  • ③ 线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

7.4 线程池的常用方法

  newCachedThreadPool(): 创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。
  
  newFixedThreadPool(int nThreads): 创建一个线程池,该线程池重用固定数量的从共享无界队列中运行的线程。
  
  newScheduledThreadPool(int corePoolSize): 创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。
  
  newSingleThreadExecutor(): 创建一个使用从无界队列运行的单个工作线程的执行程序。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值