线程相关知识[1]

参考书籍:《Java核心技术卷1》第14章

一、线程和进程

1.1 定义

进程是计算机正在执行的一个独立的应用程序,是一个动态的概念,即必须是进行状态,如果一个应用程序没有启动,就不是进程
线程是组成进程的基本单位,可以完成特定的功能,一个进程由一个或多个线程组成

1.2 区别与联系

  • 区别:
    (1)内存空间:进程是有独立的内存空间,进程之间相互独立,互不干扰;线程共享内存空间。
    (2)安全性:进程之间相互独立,一个进程的崩溃不会影响到其他的进程;线程内存共享,一个线程的崩溃可能会影响到其他线程的执行,线程的安全性不如进程
  • 联系:一个进程可以包含一个或多个线程

Java中很少用到进程概念,创建进程方式:
Runtime runtime = Runtime.getRuntime();

Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec("jps");
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String msg = null;
        while ((msg = reader.readLine()) != null){
            System.out.println(msg);
        }

java中创建线程的方式:java中多线程的创建需要调用start方法创建出新线程

private native void start0();
/**
start底层调用native修饰的start0()的方法,native需要借助于操作系统来执行,即java创建多线程的方式需要借助于底层操作系统的线程创建,线程创建交给底层C++的线程创建方式,java是对底层线程创建的封装

二、线程的创建方式

  • 继承Thread类
  • 实现Runable接口
  • 实现callable接口

2.1 继承Runable接口

Runable接口定义:

public interface Runnable {
  //抽象的run方法
    public abstract void run();
}

通过接口定义可知,通过Runable接口实现多线程就需要实现该接口中的run方法。

public class RunnableDemo implements Runnable {
    @Override
    public void run() {
        System.out.println("线程名:"+Thread.currentThread().getName()+"的线程在执行");
    }
}
public static void main(String[] args) {
        //第一种:通过实现Runnable接口来创建线程
        //执行任务体
        RunnableDemo runnableDemo = new RunnableDemo();
        //将任务体提交给线程,获取线程实例
        Thread thread = new Thread(runnableDemo);
        //当前才会创建子线程
        thread.start();
        System.out.println("main方法中线程名:"+Thread.currentThread().getName()+"线程在执行");
    }
}

实现Runnable接口创建线程的步骤:

1.创建一个特定类,必须实现Runnable接口,并实现run方法

2.实例化特定类对象

3.创建Thread类对象,将特定类对象作为参数传递

4.启动子线程,调用Thread的类的start方法

2.2 继承Thread类

Thread类的定义:

public class Thread implements Runnable{
  private Runnable target;
  
  public void run() {
        if (target != null) {
            target.run();
        }
    }
}

Thread类本身实现了Runnable的接口,即Thread类是Runnable的实现类,Thread类也有run方法,run方法来执行任务体target,需要来重写run方法
继承自Thread类的Demo:

/**
 * 继承自Thread类
 */
public class ThreadDemo extends Thread {
 
    //重写run方法
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+":子线程执行...");
    }
}
 
 
public static void main(String[] args){
 //继承自Thread类
        ThreadDemo threadDemo = new ThreadDemo();
        threadDemo.start();
        System.out.println(Thread.currentThread().getName()+":main方法所在类正在执行...");
}

继承自Thread类创建线程的方式:

1.创建特定类,继承自Thread类,重写run方法

2.实例化创建类的对象

3.调用对象的start方法启动子线程

2.3 实现Callable接口

Callable接口声明如下:

public interface Callable<V> {
    V call() throws Exception;
}

callable接口提供了call方法,具有返回值,通过泛型定义(控制返回值),该接口可以抛出异常

callable接口的不能直接使用,需要借助FutureTask类,FutureTask类可以接受Callable接口的实现类

FutureTask类定义如下:

public class FutureTask<V> implements RunnableFuture<V>{
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
}
 
public interface RunnableFuture<V> extends Runnable, Future<V>

FutureTask类是继承Runnable接口,即FutureTask是是Runnable接口的实现类,而FutureTask类提供了构造函数FutureTask(Callable callable) 可以接受Callable类型的任务,

可以实现将Callable类型实例转化为Runnable类型实例,交给Thread类处理

Callable接口的实现类Demo
public class CallableDemo implements Callable<String> {
    @Override
    public String call() throws Exception {
        System.out.println(Thread.currentThread().getName()+":子线程正在执行...");
        return null;
    }
}
 
public static void main(String[] args){
//实例化Callable接口实现类
        CallableDemo callableDemo = new CallableDemo();
        //FutureTask类实例
        FutureTask <String> futureTask = new FutureTask <>(callableDemo);
        Thread thread1 = new Thread(futureTask);
        thread1.start();
}

实现Callable接口创建线程的步骤:
1.创建特定类,实现Callable接口,实现该接口call方法
2.创建特定类的实例
3.创建FutureTask实例,将Callable实例作为参数传入
4.创建Thread对象实例,将FutureTask实例作为参数传入(当做Runnable实例)
5.启动子线程,调用Thread类对象的start方法

2.4 匿名内部类形式实现

public static void main(String[] args){
       new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+":匿名内部类实现...");
            }
        }).start();
        System.out.println(Thread.currentThread().getName()+":main方法所在类正在执行...");
    }

注: 线程的实现也可以是匿名内部类方式,可以归结为实现Runnable接口
Runnable接口和Thread类区别?
1、线程类继承自Thread则不能继承其他类(单继承),而Runnable接口可以
2、继承自Thread类相对于Runnable接口实现,创建线程的方法更简单

Callable接口和Runable接口的区别:
1、Callable接口方法为call(),而Runable接口方法为run()
2、Callable接口是有返回值,而Runable的接口的方法是不能返回值
3、call()方法是可以抛出异常的,run()是不能抛出异常
4、运行Callable任务可以拿到FutureTask的对象,通过该对象可以对子线程进行操作,获取结果.

三、线程状态及其转换

3.1 线程状态

在JDK中的Thread类中有一个子枚举类State:定义线程存在状态

public enum State {
        NEW,
        RUNNABLE,
        BLOCKED,
        WAITING,
        TIMED_WAITING,
        TERMINATED;
    }

在JDK中线程的状态有6种:

(1)新建状态(NEW)
用new语句创建的线程就处于新建状态,和Java对象一样,仅在堆中分配了内存,在调用start之前,就处于新建状态

(2)就绪状态(Runnable)
在一个线程对象创建之后,调用它的start方法,该线程就进入就绪状态,为线程创建栈和程序计数器。处于这个状态的线程位于可运行池中,等待获取CPU的执行权

(3)运行状态(Running)
处于就绪状态的线程获取了CPU的执行权,执行程序代码,只有处于就绪状态的线程才有机会到运行状态

(4)阻塞状态(BLOCKED)
在线程期望进入同步代码块或者同步方法中时会进入该状态(Synchronized或者Lock锁),等待资源(非CPU资源),等待到了资源线程就会进入就绪状态等待CPU调度

(5)超时等待(TIMED_WAITING)
如果线程执行了sleep(long time),wait(long time),join(long time),设置等待时间,当设定的等待时间到了,就会脱离阻塞状态

(6)终止状态(TERMINATED)
线程退出run()方法时,就进入终止状态,该线程结束生命周期

3.2 线程状态转换

在这里插入图片描述
一个线程的生命周期中需要状态:New、Runnable、Running和Terminated四个状态。当线程需要相应资源时,进入到阻塞状态,阻塞状态包含Blocked、Waiting、和Timed_Waiting状态

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值