一、进程与线程

进程是操作系统的概念,是程序的一次执行过程,是系统运行程序的基本单位。我们运行的一个.exe就是一个进程。具体是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,即进程空间或(虚空间),一个进程中可以启动多个线程。

线程是依附于进程而存在的,是比进程更小的执行单元,可以理解为:进程中独立运行的子任务,每一个线程必须有进程。线程拥有自己的堆栈、程序计数器和局部变量,线程和其他的线程共享进程的系统资源。

进程不能共享内存,而线程之间可以轻松地共享内存。一个程序至少有一个进程,一个进程至少有一个线程。 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

二、线程的创建

1、继承Thread类创建线程。定义Thread类的子类,并重写该类的run()方法,该方法的方法体就是线程需要完成的任务,run()方法也称为线程执行体。

2、实现java.lang.Runnable接口。void run() 使用实现接口Runnable的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的run方法。 方法run的常规协定是,它可能执行任何所需的操作。

实现 Runnable 接口

public class JueJin implements Runnable {
 
    private String name;
 
    public JueJin(String name) {
        this.name = name;
    }
 
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println(name+"掘金"+i+"%");
        }
    }
    
    public class ThreadTest {
 
    public static void main(String[] args) {
       
        Thread t = new Thread(new JueJin("抱枕"));
        Thread t1 = new Thread(new JueJin("保温杯"));
        t.start();
        t1.start();
    }
复制代码

继承 Thread 类

public class MyThread extends Thread {
 
    private String name;
 
    public MyThread(String name){
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println(name+"掘金"+i+"%");
        }
    }

public class ThreadTest {
 
    public static void main(String[] args) {
        //创建一个线程的对象
        MyThread mt = new MyThread("抱枕");
        //启动一个线程
        mt.start();
        //创建一个线程的对象
        MyThread mt1 = new MyThread("保温杯");
        //启动一个线程
        mt1.start();
    }
}
复制代码

三、线程的状态

线程状态.PNG 线程一般具有5种状态,即新建,就绪,运行,阻塞,死亡。分别如下:

新建状态:在程序中用构造方法创建了一个线程对象后,新的线程对象便处于新建状态,此时它已经有了相应的内存空间和其他资源,但还处于不可运行状态。

就绪状态:新建线程对象后,调用该线程的start()方法就可以启动线程。当线程启动时,线程进入就绪状态。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu的使用权。

运行状态:当就绪状态被调用并获得处理器资源时,线程就进入了运行状态。线程获得CPU资源正在执行任务(run() 方法),此时除非此线程自动放弃 CPU 资源或者有优先级更高的线程进入,线程将一直运行到结束。

阻塞状态:一个正在执行的线程在某些特殊情况下,如被人为挂起或需要执行耗时的输入/输出操作,会让 CPU 暂时中止自己的执行,进入阻塞状态。发生阻塞时线程不能进入排队队列,只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。阻塞的情况有三种: 调用 sleep(long t) 方法,可使线程进入睡眠方式。 一个睡眠着的线程在指定的时间过去可进入可运行(runnable)状态。

调用 wait() 方法。 调用 notify() 方法,回到就绪状态。

调用 suspend() 方法。 调用 resume() 方法,就可以恢复。

死亡状态:当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。 自然终止:正常运行完 run()方法,终止。 异常终止:调用 stop() 方法,让一个线程终止运行。

四.核心方法

sleep(long millis):线程休眠指定的时间,进入阻塞状态;

interrupt():切换线程为中断状态,抛出中断异常,不会停止线程,可以监视线程的中断状态并定义执行策略。

interrupted():清除调用该方法线程的中断状态,也不会影响线程的执行,且返回当前执行‘stopThread.interrupted()’的线程是否中断,这里就是指main线程是否中断。

isInterrupted():判断调用该方法的线程是否已经是中断状态。

使用Notify唤醒

public class WaitWithNotify {
    public static void main(String[] args) {
        Object lock=new Object();
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock){
                    System.out.println(Thread.currentThread().getName()+"获取lock");
                    try {
                        System.out.println(Thread.currentThread().getName()+"调Wait()");
                        lock.wait();
                        System.out.println(Thread.currentThread().getName()+"再次获取lock");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"Thread1").start();
        
        
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock){
                    System.out.println(Thread.currentThread().getName()+"获得lock");
                    System.out.println(Thread.currentThread().getName()+"调Notify()");
                    lock.notify();
                }
            }
        },"Thread2").start();
    }
}
复制代码

定时唤醒

public class WaitWithTime {
    public static void main(String[] args) {
        Object lock=new Object();
        new Thread(() -> {
            synchronized (lock){
                try {
                    System.out.println(Thread.currentThread().getName()+"获取lock");
                    System.out.println(Thread.currentThread().getName()+"waitting"+"currtime"+System.currentTimeMillis());
                    lock.wait(10000);
                    System.out.println(Thread.currentThread().getName()+"重新获取lock"+"currtime"+System.currentTimeMillis());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"Thread1").start();
    }
}