Java基础-线程与并发1

线程与并发 Thread

基本概念

程序: 一组计算机能识别和执行的指令 ,是静态的代码。

进程: 程序的一次运行活动, 运行中的程序 。

线程: 进程的组成部分,它代表了一条顺序的执行流。


进程线程联系:

① 线程是进程的最小执行和分配单元,不能独立运动,必须依赖于进程。众多的线程组成了进程。

② 资源分配给进程,同一进程的所有线程共享该进程的所有资源。

image-20200412123650498

进程线程区别:

① 调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位

② 并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行

③ 拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源

④ 系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,

导致系统的开销明显大于创建或撤消线程时的开销,所以使用多线程可以减小的资源开销

生命周期

image-20200412123305286

  • 新生状态:

    使用 new 关键字和 Thread 类或其子类建立一个线程对象后,该线程对象就处于新建状态。它保持这个状态直到程序 start() 这个线程。


  • 就绪状态:

    当线程对象调用了start()方法之后,该线程就进入就绪状态。就绪状态的线程处于就绪队列中,要等待JVM里线程调度器的调度。


  • 运行状态:

    如果就绪状态的线程获取 CPU 资源,就可以执行 run(),此时线程便处于运行状态。处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。


  • 阻塞状态:

    如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:

    • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。

    • 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。

    • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态,

      当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。


  • 死亡状态:

    一个运行状态的线程完成任务或者其他终止条件发生时,该线程就切换到终止状态。

创建线程的方法

继承Thread类

1.定义继承Thread的子类

2.子类重写Thread的run方法

3.实例化子类对象,创建线程

4.调用start方法,启动线程


源码

public class TestThread {
    public static void main(String[] args) {
        //创建线程方法1 继承Thread,重写run
        NewThread thread = new NewThread();
        thread.start();
        System.out.println("主线程开始打印数据");
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程:"+i);
        }
    }
}

class NewThread extends Thread{
    @Override
    public void run() {
        System.out.println("分支线程开始打印数据");
        for (int i = 0; i < 5; i++) {
            System.out.println("分支线程:"+i);
        }
    }
}

运行几次程序,发现控制台得到的结果是不一样的。这就是cpu调度的随机性。

实现Runnable接口

1.定义实现Runnable接口的子类

2.子类实现Runnable的run方法

3.通过Thread的类构造器创建线程对象

4.将Runnable实例做为实参传给构造器

5.调用Thread实例的start方法,启动线程


源码

public class TestThread {
    public static void main(String[] args) {
        //创建线程方法2 实现Runnable接口
        Thread thread = new Thread(new NewRunnable());
        thread.start();
        System.out.println("主线程开始打印数据");
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程:"+i);
        }
    }
}

class NewRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("分支线程开始打印数据");
        for (int i = 0; i < 5; i++) {
            System.out.println("分支线程:"+i);
        }
    }
}

两种创建方法的区别

  1. 采用实现 Runnable接口的方式创建多线程时,线程类只是实现了 Runnable 接口,还可以继承其他类。(推荐)
  2. 多个线程可以共享同一个Runnable实现类的对象,利于资源同步。
  3. 使用继承 Thread 类的方式创建多线程时,如果需要访问当前线程,直接使用 this 即可获得当前线程。

Thread类

构造方法


image-20200412131959700


常用方法

方法 功能描述
public void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法。
public void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
public final void setName(String name) 改变线程名称,使之与参数 name 相同。
public final void setPriority(int priority) 更改线程的优先级。
public final void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。
public final void join(long millisec) 等待该线程终止的时间最长为 millis 毫秒。
public void interrupt() 中断线程。 stop()已过时。
public final boolean isAlive() 测试线程是否处于活动状态。
public final synchronized void join(long millis) 等待该线程终止的时间最长为 millis 毫秒
public static void yield() 线程让步,暂停当前正在执行的线程对象,并执行其他线程。
public static void sleep(long millisec) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。
public static Thread currentThread() 返回对当前正在执行的线程对象的引用。

优先级

 /**  * The minimum priority that a thread can have.  */ 
public final static int MIN_PRIORITY = 1;

/**  * The default priority that is assigned to a thread.  */ 
public final static int NORM_PRIORITY = 5; 

/**  * The maximum priority that a thread can have.  */ 
public final static int MAX_PRIORITY = 10;

范围1-10,数字越大系统调用的概率越高。默认优先级为5。


实例测试代码

public class FunctionTest {
    public static void main(String[] args) throws InterruptedException {
        Thread threadChild = new NewThread();
        Thread threadRun = new Thread(new NewRunnable(),"线程2  ");
		//先设置优先级
        threadChild.setPriority(1);
        threadRun.setPriority(10);
		//启动线程
        threadChild.start();
        threadRun.start();
		//获取线程属性
        threadChild.setName("线程1  ");
        System.out.println(threadChild.getName());
        System.out.println(threadRun.getName());
        System.out.println(Thread.currentThread().getName());

        if (threadChild.isAlive())
            System.out.println(threadChild.getName()+"活着");

        System.out.println("------有人在中间插队------");
        threadChild.join();//执行完毕才到下一行
        System.out.println("------有人在中间插队------");
		//打印线程状态
        threadRun.interrupt();
        System.out.println(threadChild.isAlive());
        System.out.println(threadRun.isAlive());

    }
}

后记

以上内容仅仅是很基础的概念认识。

实际应用中会遇到很多问题,比如:

  • 线程同步
  • 线程间通信
  • 线程死锁
  • 线程控制:挂起、停止和恢复

猜你喜欢

转载自www.cnblogs.com/1101-/p/12684973.html