多进程(1)

自作多情 提交于 2020-03-08 22:21:07

多线程

1.认识线程
1.1概念
  • 进程是系统分配资源的最小单位
  • 线程是系统调度的最小单位
  • 一个进程内的线程之间是可以共享资源的
  • 每个进程内至少有一个线程存在,即主线程

进程和线程的区别?
1.进程是系统分配资源的最小单位
2.线程是系统调度的最小单位
3.一个进程中的各个线程之间共享 方法区(常量池)、堆

线程也存在并发、并行

代码1:

public static void main(String[] args) throws InterruptedException {
        Thread.sleep(9999999L);
}

使用jconsole命令观察线程
在这里插入图片描述
代码2:

public static void main(String[] args) throws InterruptedException {
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                Thread.sleep(9999999L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }).start();
}

使用jconsole命令观察线程
在这里插入图片描述
代码1的线程名字是 main ,而代码2的线程名字是 Thread-0
原因如下:

Java 程序启动的流程:
把 java 文件名作为参数 传给 java
java.exe 启动
(1) 调用系统api分配进程的资源
(2) 调用系统级别C语言main方法(启动一个主线程,系统级别)每个进程至少有一个线程存在,即主线程
(3) 启动主线程后,调用 initialize_JVM :初始化 java 虚拟机参数
create_VM:根据初始化参数创建 java 虚拟机
启动 jvm 内部的守护线程(后台线程):如垃圾回收线程等等
调用 java 代码中 main 方法(启动Java main 方法)
java 级别的 main 方法可以退出

Java级别的线程创建 本质上 还是要 调用操作系统级别的线程创建 系统级别的创建 是非常耗时的

多线程的优势:增加运行速度

public class Test {
//线程并不一定就能提高速度,可以观察,COUNT、NUM不同,运行效果也不同
    private static final int COUNT = 10_0000_0000;
    private static final int NUM = 2;
    public static void sum() {
        int b = 0;
        for (int i = 0; i < COUNT; i++) {
            b--;
        }
    }
    public static void concurrency() {
        //并发
        long start = System.nanoTime();
        for (int i = 0; i <NUM ; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    sum();
                }
            }).start();
        }
        //等待当前线程结束
        while (Thread.activeCount()>1) {
            Thread.yield();// 将当前线程由 运行态-->就绪态
        }
        long end = System.nanoTime();
        System.out.printf("并发执行的时间为%d毫秒\n",end-start);
    }
    public static void serial() {
        //串行
        long start = System.nanoTime();
        for (int i = 0; i <NUM ; i++) {
            sum();
        }
        long end = System.nanoTime();
        System.out.printf("串行执行的时间为%d毫秒\n",end-start);
    }
    public static void main(String[] args) {
        //使用并发方式
        concurrency();
        //使用串行方式
        serial();
    }
}

在这里插入图片描述

1.2 创建线程

方法1:继承 Thread

class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class Test2 {

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

方法2:实现 Runnable 接口

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
Thread t = new Thread(new MyRunnable());
t.start();    //线程开始运行

方法3:匿名类创建 Thread 子类对象

Thread t = new Thread() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
        }
    };

方法4:匿名类创建Runnable 子类对象

Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
2.Thread 类及常见方法
2.1 构造方法

创建线程:

Thread()

使用Runnable对象创建线程对象

Thread(Runnable target)

创建线程对象,并命名

Thread(String name)

使用Runnable对象创建线程对象 并命名

Thread(Runnable target,String name)
2.2 属性

在这里插入图片描述

  • ID 是线程的唯一标识,不同线程不会重复
  • 优先级更高的线程,更有可能先执行,但不是一定,只是几率大
  • JVM会在一个进程的所有非后台线程结束后,才会结束运行
  • 是否存活就是 run() 方法是否运行结束了
2.3 线程的run()start()
class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
public class Test2 {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        //run()直接调用,不会启动线程
        //只是在当前的 main 线程中调用run()方法
        myThread.run();
        //调用 start() 方法是启动了线程
        //myThread.start();
    }
}
2.4 守护线程

守护线程的运行条件

  • 至少有一个非守护线程,进程不会退出

非守护线程一般称为 工作线程
守护线程一般称为 后台线程
设置为守护线程

setDaemon(true)
2.5 常用方法

将当前进程由运行态---->就绪态 线程的让步

//等待当前线程结束
while (Thread.activeCount()>1) {
   Thread.yield();// 将当前线程由 运行态-->就绪态
}

将当前进程由运行态---->阻塞态 等待(当前进程自行运行)

join()
join(long millon)

无参数:等待当前线程执行完毕
有参数:

  1. 和时间参数相比
  2. 如果时间参数比线程运行时间长,那就让当前线程执行完毕
  3. 如果时间参数比线程运行时间短,那就执行下面的线程

activeCount()yield() 组合可以实现 join() 等待线程

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!