Java线程基础

本文详细解析了进程与线程的概念,探讨了它们的创建、生命周期和关键区别,包括资源分配、通信效率、创建成本和稳定性。涵盖了线程创建的多种方式,如继承Thread、实现Runnable和Callable接口,以及线程生命周期的各个阶段。
摘要由CSDN通过智能技术生成

线程和进程的概念

进程和线程的认识

1)进程指的一段正在运行的程序一个程序运行中可以执行过个任务,任务称之为线程。
2)进程是程序执行过程中资源分配和管理的基本单位,线程是cpu执行最小单位。进程拥有自己的独立的地址空间,每启动一个进程,系统就会分配地址空间。进程可以拥有多个线程,各个线程之间共享程序的内存空间。
为什么出现线程?
每个进程有自己独立的地址空间,多并发请求,为每一个请求创建一个进程,从而导致系统开销、用户请求效率低。

多线程和多进程的区别

1)每个进程拥有自己独有的数据,线程共享数据,线程之间的通信相比于进程之间的通信更有效、更容易
2)线程相比于进程创建/销毁开销更小
3)进程是资源分配的最小单位,线程是cpu调度的最小单位
4)多进程程序更加健壮,多线程程序只要有一个线程挂掉,对其共享资源的其他线程也会产生影响
5)如果追求速度,选择线程;如果频繁创建和销毁,选择线程;如果追求系统更加稳定,选择进程。线程是轻量级的进程。

线程的创建

1)继承Thread类,重写run()方法
2)实现Runnable接口,重写run方法
3)匿名线程,匿名内部类
4) 实现Callable接口,重写call方法。Callable接口存在Executor框架中类,相比于Runnable更加强大
a.Callable可以在任务执行结束之后提供一个返回值
b.call方法可以抛出异常
c.运行Callable任务可以拿到一个Future对象,Future提供get方法拿到返回值(异步)
通过Callable和FutureTask创建线程:
a.创建Callable接口的实现类,重写call方法
b.创建Callable实现类的实例,使用FutureTask包装该实例
c.将FutureTask实例作为参数创建线程对象
d.启动该线程
e.调用FutureTask的get方法获取子线程的执行结果

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class MyThread extends Thread{
    @Override
    public void run() {
        //线程执行体
        while(true){ //1
            System.out.println("eat food");//2
        }
    }
}
class MyRunnable implements Runnable{

    @Override
    public void run() {
        //线程执行体
        while(true){ //1
            System.out.println("eat food");//2
        }
    }
}
class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for(int i=0; i<10000; i++){
            sum += i;
        }
        return sum;
    }
}
public class TextDemo1 {
    //main  1  2 3
    //子    1 2
    public static void main(String[] args) {
        Callable<Integer> callableTask = new MyCallable();
        FutureTask<Integer> task = new FutureTask<>(callableTask);
        Thread thread = new Thread(task);
        thread.start();

        //接受线程执行之后的结果
        try {
            Integer integer = task.get();
            System.out.println("result: "+integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        //extends Thread创建子线程
//        //创建子线程对象
//        Thread thread = new MyThread(); //1
//        //启动吃饭的thread
//        thread.start(); //start -> run //2
//        //implements Runnable创建子线程
//        //创建子线程对象,将Runnable实例作为参数实例化子线程对象
//        Thread thread = new Thread(new MyRunnable());
//        //启动吃饭的thread
//        thread.start();

//        //main线程
//        while(true){
//            System.out.println("watch TV"); //3
//        }
//        new Thread(){
//            @Override
//            public void run() {
//                System.out.println("thread-0");
//            }
//        }.start();
    }
}

线程的生命周期

new(新建状态):new关键字创建一个线程对象,它并不是处于一个执行状态,因为还没有start启动线程
Runnable(就绪状态):线程对象调用start方法,才是在JVM中真正创建了一个线程,线程一经启动并不会立即执行,该状态的所有线程位于就绪线程池中,等待操作系统的资源,如:处理器,获得cpu的使用权
Blocked(阻塞状态):等待一个监视器锁进入同步代码块或者同步方法,代码块/方法某一时刻只能够有一个线程执行,其他线程只能等待
Waiting(等待状态):Object.wait()/Thread.join()/LockSupport.park()都会使得线程阻塞,从Runnable转换到Waiting状态
Timed_Waiting(睡眠状态):调用加超时参数的Object.wait(long mills)/Thread.slepp(long mills)/LockSupport.
parkNano()/LockSupport.parkUntil()
Terminated(终止状态):是一个线程的最终状态,线程进入到Terminated状态,意味着该线程的生命周期结束了,下面这些情况都会使得线程进入Terminated状态
1)线程执行正常结束
2)线程运行出错意外结束
3)JVM crash

线程中的常用方法

1)start()
启动一个线程,将线程添加一个线程组中,线程状态会从New状态转换到Runnable状态,然后获取Cpu之后进入Running状态执行run
2)sleep()
sleep是一个静态方法,其中存在两个重载函数

  • public static native void sleep(long millis)
  • public static void sleep(long millis, int nanos)
    使得线程进入睡眠状态,暂停执行,sleep不会放弃monitor lock的所有权。jdk1.5之后,jdk引入一个枚举TimeUnit,其对sleep方法做了封装,直接使用从而省去时间单位换算的步骤,比如线程睡眠3h27min8sec88msec
    3)yield()
    yield表示提醒cpu调度器我愿意放弃当前的cpu资源,(属于启发式方法),如果cpu资源不紧张的情况下,会忽略这种提示
    yield和sleep的区别
    a.jdk1.5之前,yield调用了sleep
    b.sleep使得当前线程暂停执行,不会占用cpu资源,yield只是对于cpu调度器的一个提示
    c.sleep会导致线程短暂的阻塞,yield会使得线程Runnable-》Runnable
    d.sleep会捕获到中断异常,yield不会捕获到中断异常
    4)join()
    含义:在线程B中join某个线程A,会使得B线程进入等待,直到线程A结束生命周期,或者达到给定的时间,在这期间线程B会处于等待状态
class ThreadDemo extends Thread{
    private Thread thread;
    private String name;

    public ThreadDemo(Thread thread, String name){
        this.name = name;
        this.thread = thread;
    }
    @Override
    public void run() {
        if(thread != null){
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        for(int i=1; i<=10; i++){
            System.out.println(name +"::" +i);
        }
    }
}
public class TestDemo4 {
    public static void main(String[] args) {
        //A,B,C三个线程  使得A,B,C三个线程顺序打印1~10
        ThreadDemo A = new ThreadDemo(null, "线程A");
        ThreadDemo B = new ThreadDemo(A, "线程B");
        ThreadDemo C = new ThreadDemo(B, "线程C");
        A.start();
        B.start();
        C.start();
    }
}

5)wait()
调用某个对象的wait()方法可以让当前线程阻塞
6)notify()和notifyAll()
调用当前对象notify/notifyAll才能够唤醒这个对象所在的线程
8)线程中断方法
每个Java线程都会有一个中断状态位,程序可以检测这个中断状态位判读线程是否执行结束
a.interrupt()
public void interrupt() 由线程对象调用,将中断位置置为true。
如下方法能够使得当前线程进入阻塞状态,调用interrupt方法可以打断阻塞,因此这种方法被称之为可中断方法

  • Object.wait()/wait(long)
  • Thread.sleep(long)/TimUnit.XXX.sleep(long)
  • Thread.join()/Thread.join(long)

interrupt:如果一个线程被interrupt,设置interrupt flag;如果当前线程正在执行可中断方法,调用interrupt方法,反而导致interrupt flag被清除
b.isInterrupted判断当前线程的中断状态位是否为true
c.interrupted
public static Boolean interrupted() 静态方法
调用interrupted会擦除中断状态位的标识

public class TextDemo5 {
    public static void main(String[] args) {
        Thread thread = new Thread(){
            @Override
            public void run() {
                while(true){
                    System.out.println(Thread.interrupted());
                }
            }
        };
        thread.setDaemon(true);
        thread.start();

        try {
            TimeUnit.MILLISECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
        
        
        Thread thread1 = new Thread(){
            @Override
            public void run() {
                while(true){
                    try {
                        TimeUnit.MILLISECONDS.sleep(1); //sleep会擦除中断状态位
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread1.start();
        try {
            TimeUnit.MILLISECONDS.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread is interrupted: "+thread1.isInterrupted());
        thread1.interrupt();
        System.out.println("Thread is interrupted: "+thread1.isInterrupted());

        Thread thread2 = new Thread(){
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(10); //使得子线程进入阻塞状态
                    //interrupt方法会打断这种阻塞,会抛出异常
                } catch (InterruptedException e) {
                    System.out.println("I am be interrupted");
                }
            }
        };
        thread2.start();

        try {
            TimeUnit.MILLISECONDS.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread2.interrupt();

        Thread thread3 = new Thread(){
            @Override
            public void run() {
                while(true){
                    System.out.println("test interrupt");
                    try {
                        TimeUnit.MILLISECONDS.sleep(100);
                    } catch (InterruptedException e) {
                        //e.printStackTrace();
                        System.out.println(Thread.currentThread().isInterrupted());
                    }
                }
            }
        };
        thread3.start();
        thread3.interrupt(); //将thread的中断状态位置为true
        System.out.println("Thread interrupt flag: "+thread3.isInterrupted());
        //sleep 可中断方法能够清除原本线程置为true的中断状态位
        String strs = new String("test wait");

//        new Thread("A"){
//            @Override
//            public void run() {
//                synchronized (strs){
//                    //同步代码块
//                    try {
//                        strs.wait(); //释放当前对象的monitor lock -》Waiting
//                        //表示让当前线程进入到阻塞状态
//                        System.out.println("the currend thread name is "+Thread.currentThread().getName());
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                }
//            }
//        }.start();
//
//
//        new Thread("B"){
//            @Override
//            public void run() {
//                synchronized (strs){
//                    //strs.notify();//随机唤醒其中一个
//                    strs.notifyAll(); //唤醒所有线程 然后所有线程开始抢锁
//                }
//            }
//        }.start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值