并发编程基础(Ⅰ)

基础

线程的声明周期

Java 线程既然能够创建,那么也势必会被销毁,所以线程是存在生命周期的,可以从线程的生命周期开始去了解线程

线程一共有 6 种状态:NEW、RUNNABLE、BLOCKED、WAITING、TIME_WAITING、TERMINATED

NEW:初始状态,线程被构建,但是还没有调用 start 方法

RUNNABLE:运行状态,JAVA 线程把操作系统中的就绪和运行两种状态统一称为“运行中”

BLOCKED:阻塞状态,表示线程进入等待状态,也就是线程因为某种原因放弃了 CPU 使用权,阻塞也分为几种情况
1)等待阻塞:运行的线程执行 wait 方法,jvm 会把当前线程放入到等待队列
2)同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被其他线程锁占用了,那么 jvm 会把当前的线程放入到锁池中
3)其他阻塞:运行的线程执行 Thread.sleep 或者 t.join 方法,或者发出了 I/O 请求时,JVM 会把当前线程设置为阻塞状态,当 sleep 结束、join 线程终止、io 处理完毕则线程恢复

WAITING:等待状态

TIMED_WAITING:超时等待状态,超时以后自动返回

TERMINATED:终止状态,表示当前线程执行完毕

线程6种状态.png

演示代码的状态:

public class ThreadStatus {
    public static void main(String[] args) {
        //TIME_WAITING
        new Thread(()->{
            while(true){
                try {
                    TimeUnit. SECONDS .sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"timewaiting").start();
        //WAITING,线程在 ThreadStatus 类锁上通过 wait 进行等待
        new Thread(()->{
            while(true){
                synchronized (ThreadStatus.class){
                    try {
                        ThreadStatus.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"Waiting").start();
        //线程在 ThreadStatus 加锁后,不会释放锁
        new Thread(new BlockedDemo(),"BlockDemo-01").start();
        new Thread(new BlockedDemo(),"BlockDemo-02").start();
    }
    
    static class BlockedDemo extends Thread{
        public void run(){
            synchronized (BlockedDemo.class){
                while(true){
                    try {
                        TimeUnit. SECONDS .sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

启动一个线程前,最好为这个线程设置线程名称,因为这样在使用 jstack 分析程序或者进行问题排查时,就会给开发人员提供一些提示

线程的生命周期,在整个生命周期中并不是固定的处于某个状态,而是随着代码的执行在不同的状态之间进行切换

线程启动的原理

线程的启动,也就是调用start()方法去启动一个线程,当 run 方法中的代码执行完毕以后,线程的生命周期也将终止。调用 start 方法的语义是当前线程告诉 JVM,启动调用 start 方法的线程

线程的应用

如何应用多线程?

在 Java 中,有多种方式来实现多线程:继承 Thread 类、实现 Runnable 接口、使用 ExecutorService、Callable、Future 实现带返回结果的多线程

  • 继承Thread类创建线程

Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。启动线程的唯一方法就是通过 Thread类的 start()实例方法。start()方法是一个 native 方法,它会启动一个新线程,并执行 run()方法

这种方式实现多线程很简单,通过自己的类直接 extend Thread,并复写 run()方法,就可以启动新线程并执行自己定义的 run()方法

  • 实现Runnable接口创建线程
    如果自己的类已经 extends 另一个类,就无法直接 extends
    Thread,此时,可以实现一个 Runnable 接口
public class MyThread extends OtherClass implements Runnable {
    public void run() {
        System.out.println("MyThread.run()");
    }
}
  • 实现 Callable 接口(call方法)通过 FutureTask 包装器来创建 Thread 线程
public class CallableDemo implements Callable {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        CallableDemo callableDemo=new CallableDemo();
        Future future=executorService.submit(callableDemo);
        System. out .println(future.get());
        executorService.shutdown();
    }

    @Override
    public Object call() throws Exception {
        int a=1;
        int b=2;
        System. out .println(a+b);
        return "执行结果:"+(a+b);
    }
}

你可能感兴趣的:(并发编程基础(Ⅰ))