• 线程学习笔记(一)


    一、引入多线程

    多线程

    请看上图中的代码执行流程,就可以大概的理解多线程。说到多线程就一定会联系到单线程,所谓单线程就是程序只有一条执行路径。相反,多线程就是程序有多条执行路径。

    二、进程的概述

    1.要想了解多线程,必须先了解线程。了解线程就必须先了解进程。因为线程依赖于进程。

    2.什么是进程:就是正在运行中的程序。进程是系统进行资源分配和调度的独立单位,每一个进程都有自己独立的内存空间和系统资源。

    3.多进程的意义:在同一时间段内可以执行多个任务,极大的提高了CPU的使用率。单核的CPU在某一时刻只能执行一个任务。

    三、线程的概述

    1.什么是线程:在同一个进程中又可以执行多个任务,而这每一个任务可以看成一个线程。线程是程序执行路径和执行单元,是程序使用CPU的基本单元。

    2.多线程的意义:不是提高程序的执行速度的,而是提高应用程序的使用率的。程序的执行其实都在抢CPU资源和CPU的执行权。多个进程都在争夺CPU这一资源,而其中一进程有多个执行路径,抢到这一资源的几率就更高。但线程的执行是由随机性的。

    四、并行和并发

    并行:逻辑上同时发生,是指在同一时间内同时运行多个程序。

    并发:物理上同时发生,是指在同一时间点上同时运行多个程序。

    五、Java程序运行原理

    执行Java命令就会启动Java虚拟机,启动JVM就等于启动了一个应用程序,也就是启动了一个进程,该进程会自动启动一个主线程。然后,主线程会去调用某个类的main方法,所以main方法时运行在主线程中的。

    多线程

    通过上图,可以看到启动一个Java程序,就会启动一个线程,在该线程中调用main方法。

    JVM的启动是多线程的:在运行一个Java程序的时候,在启动主线程的时候,也会启动垃圾回收线程,否则会出现内存溢出。

    六、创建线程的方式

    1. 继承java.lang.Thread类,重写run()方法,创建线程对象并启动线程。

    package com.jd;
    
    /**
     * Created by shifeifei on 2015/8/12.
     */
    public class MyThread extends Thread {
        public static void main(String[] args) {
            MyThread t = new MyThread();
            /**
             * run():仅仅是封装了线程执行的代码,直接调用就是普通方法
             * start():首先启动了线程,然后由JVM去调用run()方法
             */
            t.start();
    
            /**
             *要启动多个线程,必须先创建多个线程对象,再调start()方法
             */
            MyThread t2 = new MyThread();
            t2.start();
        }
    
        @Override
        public void run() {
            for(int i=0;i<200;i++) {
                System.out.println("当前线程是:"+ this.getName() + " " + i);
            }
        }
    }

    获取线程名称的方法是:public final String getName(),该方法返回的线程名称形式是:Thread-?(?代表0、1、2等自然数),为什么会是这种形式呢?我们开源码解析:

    由于MyThread类继承与Thread类,进入到Thread类,我们可以看到如下代码:

        private static int threadInitNumber;
    
        public Thread() {
            init(null, null, "Thread-" + nextThreadNum(), 0);
        }
    
        private static synchronized int nextThreadNum() {
            return threadInitNumber++;
        }
        
        private char    name[];
        
        private void init(ThreadGroup g, Runnable target, String name,
                          long stackSize) {
            this.name = name.toCharArray();
        }
        
        public final String getName() {
            return String.valueOf(name);
        }

    即在创建线程对象的时候,就调用init()方法。

    既然能够获取线程的名称,我们也能够设置线程的名称,常用的方式有两种:调用public final void setName(String name)和

    public Thread(String name)
    • 线程调度

       (1) 分时调度模型:所有线程轮流使用CPU的执行权,平均分配每个线程占用CPU的时间片。

       (2) 抢占式调度模型:优先级高的线程优先使用CPU执行权,如果线程的优先级相同,就会随机选择一个执行,优先级高的线程获取CPU使用权多一些。

       (3) Java中使用抢占式调度模型。

        线程的优先是从1 - 10,默认的优先级为 5.Thread类定义了2个常量:MIN_PRIORITY和MAX_PRIORITY来表示最高和最低优先级。

        1.获取线程的优先级:public final int getPriority()

        2.设置线程的优先级:public final void setPriority(int newPriority)

    package com.jd;
    
    /**
     * Created by shifeifei on 2015/8/13.
     * */
    public class ThreadPriority extends Thread {
        @Override
        public void run() {
            for(int i=0;i<100;i++) {
                System.out.println(this.getName() + " " + i);
            }
        }
    
        public static void main(String[] args) {
            ThreadPriority t1 = new ThreadPriority();
            ThreadPriority t2 = new ThreadPriority();
            System.out.println(t1.getPriority() + " " + t2.getPriority());
            t1.start();
            t1.setPriority(10);
            t2.start();
            t2.setPriority(1);
        }
    }

    3.线程信息

    package com.jd;
    
    /**
     * Created by shifeifei on 2015/8/12.
     */
    public class MyTestOne {
        public static void main(String[] args) {
            //Thread.currentThread()返回当前线程的引用
            String name = Thread.currentThread().getName();
            int priority = Thread.currentThread().getPriority();
            String groupName = Thread.currentThread().getThreadGroup().getName();
    
            boolean isDaemon = Thread.currentThread().isDaemon();
    
            System.out.println("线程名字: " + name);
            System.out.println("线程优先级: " + priority);
            System.out.println("线程组名称: " + groupName);
            System.out.println("是否为守护线程: " + isDaemon);
        }
    }
    • 守护线程和用户线程

          1. 守护线程:Java程序运行时后台提供的一种通用服务的线程。守护线程是用来服务用户线程的,如果全部的用户线程结束了,守护线程也就结束了。

    package com.jd;
    
    /**
     * Created by shifeifei on 2015/8/12.
     */
    public class MyThread extends Thread {
        public static void main(String[] args) {
    
            Thread t1 = new Thread("daemon") {
                @Override
                public void run() {
                    Thread t2 = new Thread("sub") {
                        @Override
                        public void run() {
                            for (int i = 0; i < 20; i++) {
                                System.out.println(this.getName() + " " + i);
                            }
                        }
                    };
                    t2.setDaemon(true);
                    t2.start();
                }
            };
            t1.start();
        }
    }

          注意:(1) 所有的用户线程结束时,JVM就可以退出了。

                  (2) 设置当前线程为守护线程时必须在start()方法之前。

                  (3) 在Daemon线程中产生的新线程也是Daemon的。

                  (4) 守护线程应该永远不去访问固有资源,如文件、数据库,因为它会在任何时候甚至在一个操作的中间发生中断。

    • GroupName,每个线程都会默认在一个线程组里,我们也可以显式的创建线程组,一个线程组中也可以包含子线程组,这样线程和线程组,就构成了一个树状结构。
  • 相关阅读:
    java学习大方向
    js总结001
    MySQL总结
    快捷键
    java基础总结001
    网络设备的发展与作用(冲突域与广播域)
    二进制&八进制&十六进制之间的快速转换------ 心算&笔算方法总结
    IP地址的定义和划分
    初学Linux基本的命令操作应当记牢
    JDK的下载与安装
  • 原文地址:https://www.cnblogs.com/shi-blog/p/4726453.html
Copyright © 2020-2023  润新知