Java基础—多线程

1.进程:

1.进程可以理解成线程的容器,一个进程执行必须至少要一条线程。

2.进程可以理解为一个程序的执行

2.线程:

1.CPU分配资源是以线程为单位

2.

3.关注点

1.进程间不能相互通信,但是同一个进程的多个线程之间可以共享数据。

4.并发和并行

1.并发:单核CPU同一时间只能处理一条线程,但是速度非常快,造成并行的假象(例子:开车打电话)

2.并行:多核CPU,每个核心单独执行一个线程。

5.多线程的优势

1.多线程可以提高CPU的利用率

注意:单核CPU不能提高,反而降低

2.可以实现异步调用

6.创建多线程的三种方式

线程在Java中也是一种对象

1.继承Thread,重写Run方法

        创建线程对象

        调用线程对象的Start方法将当前线程加入到CPU的执行任务队列

注意:不要调用线程对象的RUN方法,这个方法是给CPU来调用的,我们只负责把当前线程加入到CPU的执行队列中。

*问题:run与Start:总结起来就是run()就是一个普通的方法,而start()会创建一个新线程去执行run()的代码

package MyThread;

public class MyThread01 extends Thread{
    //第一种创建线程的方法:new Thread 继承Thread


    @Override
    public void run() {
        System.out.println("Thread hello");
    }
}

class MyThread02{
    public static void main(String[] args) {
        MyThread01 m1 = new MyThread01();
        m1.start();
    }
}

2.Runnable接口

第二种方式:

1.线程类实现Runnable接口

2.重写Run方法

3.new线程类对象

4.new Thread对象,把线程类对象加载进去,再调用Start

package MyThread;

public class MyRunnable01 implements Runnable{
    @Override
    public void run() {
        System.out.println("Hello,Runnable");
    }
}

class MyRunnable02{
    public static void main(String[] args) {
        MyRunnable01 m01 = new MyRunnable01();

        Thread thread = new Thread(m01);
        thread.start();
    }
}

对比:

1.Thread和Runnable 推荐第二种 因为Runnable没有继承父类

2.Thread将线程对象和线程所有执行的任务耦合在一起了,不符合面向对象的规范

约等于使用构造器解耦

还可以使用匿名内部类的方式

//匿名内部类
class MyRunnable03{
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("你好,Runnable");
            }
        }).start();
    }
}

第三种方式:Callable接口:jdk5新增的

1.创建线程类,实现Callable接口,重写Call方法,设置泛型返回值

2.实现逻辑代码,并返回

3.使用FutureTake 把Callable转成Runnable

4.将参数传给Thread

注意:为什么用FutureTake 把Callable转成Runnable就可以了?

Thread可以接收Runnable是因为构造方法重载了一个有Runnable接口的参数

package MyThread;

import java.lang.reflect.Member;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

public class MyCallable01 implements Callable {
    @Override
    public Object call() throws Exception {
        int sum = 7;
        System.out.println("Hello Callable");
        return sum;
    }
}

class MyCallable02{
    public static void main(String[] args) throws Exception {
        MyCallable01 c1 = new MyCallable01();

        FutureTask ft = new FutureTask(c1);

        Thread t1 = new Thread(ft);

        t1.start();

        System.out.println(ft.get());


    }
}

7.线程常用方法介绍:

  • currentThread():这是线程类的一个静态方法,获取执行当前任务的线程对象

  • getName():获取线程的名称,每个线程都有自己的名字【唯一标识】

    系统默认的线程名称规则:主线程就叫main 其他线程:thread-index

  • setName(name):设置线程对象的名称 也可以通过构造器初始化name的值

  • getPriority():获取线程对象的执行优先级

  • setPriority():设置线程对象的执行优先级 默认为5

  • sleep(毫秒数):也是一个线程类的静态方法,让调用这个方法的当前线程休眠

  • join():线程合并 整个JAVA程序只要还有线程没结束,程序就不会结束

  • stop():强制结束线程【过于暴力 不安全】

  • interrupt():打断指定的线程

  • isInterrupted():获取线程是否被打断的标记

  • (1)sleep() 方法是 Thread 类中的方法,而 wait() 方法是 Object 类中的方法。

    (2)sleep() 方法不会释放 lock,但是 wait() 方法会释放,而且会加入到等待队列中。

    (3)sleep() 方法不依赖于同步器 synchronized(),但是 wait() 方法 需要依赖 synchronized 关键字。

    (4)线程调用 sleep() 之后不需要被唤醒(休眠时开始阻塞,线程的监控状态依然保持着,当指定的休眠时间到了就会自动恢复运行状态),但是 wait() 方法需要被重新唤醒(不指定时间需要被别人中断)。
     

8.线程守护

        通过方法Thread.setDaemon();

package MyThread;

public class MyDaemon extends Thread{
    @Override
    public void run() {
        for (int i = 0;i<10;i++) {
            System.out.println("我是主线程");
        }
    }
}

class Mydaemon02 implements Runnable{

    @Override
    public void run() {
        while (true){
            
            System.out.println("我是守护线程");

        }
    }
}
class MyDaemon01{
    public static void main(String[] args) {
        new MyDaemon().start();
        Mydaemon02 mydaemon02 = new Mydaemon02();
        Thread thread = new Thread(mydaemon02);
        thread.setDaemon(true);
        thread.start();
    }}

9.线程生命周期

Java基础—多线程_第1张图片

1.新建状态(NEW)

当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配 内存,并初始化其成员变量的值 。
2.就绪状态(RUNNABLE)

当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和 程序计数器,等待调度运行。
3.运行状态(RUNNING)

如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态。
4.阻塞状态(BLOCKED)

阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。 直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状 态。阻塞的情况分三种:

(1)等待阻塞 ( o.wait-> 等待对列 )

运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue) 中。

(2)同步阻塞 (lock-> 锁池 )

运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线 程放入锁池(lock pool)中。

(3)其他阻塞 (sleep/join)

运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时, JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O 处理完毕时,线程重新转入可运行(runnable)状态。
5.线程死亡(DEAD)

线程会以下面三种方式结束,结束后就是死亡状态。

    正常结束: run()或call()方法执行完成,线程正常结束。
    异常结束: 线程抛出一个未捕获的Exception或Error。
    调用 stop: 直接调用该线程的stop()方法来结束该线程— 该方法通常容易导致死锁,不推荐使用。

10.线程安全

线程安全发生的条件:

        1.线程并发

        2.多线程之间要有数据共享【每个线程独享栈,共享堆】

        3.要有对共享数据的读写操作

        4.发生读写的指令交错【可能发生也可能不发生】

*解决线程安全:

        1.Synchronize

        2.Lock

使用方法:

线程创建栈

Java基础—多线程_第2张图片

 11.线程通信

为什么需要线程通信:

        线程是操作系统调度的最小单位,有自己的栈空间,可以按照既定的代码逐步的执行,但是如果每个线程间都孤立的运行,那就会造资源浪费。所以在现实中,我们需要这些线程间可以按照指定的规则共同完成一件任务,所以这些线程之间就需要互相协调,这个过程被称为线程的通信。

  • wait():导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法
  • notify():唤醒正在等待对象监视器的单个线程
  • notifyAll():唤醒正在等待对象监视器的所有线程

这三个方法不属于线程,所有对象都可以调用

12.Lock锁

Java1.5后的接口

13.线程池

线程池的使用:

        顶级接口:execute里面之定义了一个方法,开发中不会直接使用

        我们一般使用他的一个子接口:ExecutorService

        重要方法:submit():向线程池提交任务对象

                          shutdown():关闭线程池

                          shutdownNow():立刻马上关闭

                          isTerminated():判断线程池是否关闭

        实现类:ThreaddPoolExecutor

        创建线程池核心方法:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {

线程池的工作流程:

        1.启动核心线程

        2.如果任务太多并且核心线程全部占满(先压任务,如果还是解决不了再创建救急线程)

        3.如果队列满了,创建救济线程

        4.如果救济线程达到最大数量则执行拒绝策略

        

你可能感兴趣的:(Java基础,java,jvm,开发语言)