zoukankan      html  css  js  c++  java
  • 线程原理 创建方式

    线程

    1.1 多线程原理

    先画个多线程执行时序图 来体现一下多线程程序的执行流程。

    代码如下:

    自定义线程类:

    public class MyThread extends Thread{
        /*
        * 利用继承中的特点 
        * 将线程名称传递 进行设置 
        */ 
        public MyThread(String name){ 
            super(name); 
        }
        /*
        * 重写run方法 
        * 定义线程要执行的代码 
        */ 
        public void run(){ 
            for (int i = 0; i < 20; i++) {
                //getName()方法 来自父亲
                System.out.println(getName()+i);
            } 
        } 
    }
    

    测试类:

    public class Demo {
        public static void main(String[] args) {
            System.out.println("这里是main线程");
            MyThread mt = new MyThread("小强");
            mt.start();//开启了一个新的线程 
            for (int i = 0; i < 20; i++) {
                System.out.println("旺财:"+i);
            } 
        } 
    }
    

    流程图:

    程序启动运行main时候,java虚拟机启动一个进程,主线程main在main()调用时候被创建。随着调用mt的对象的

    start方法,另外一个新的线程也启动了,这样,整个应用就在多线程下运行。

    通过这张图我们可以很清晰的看到多线程的执行流程,那么为什么可以完成并发执行呢?我们再来讲一讲原理。

    多线程执行时,到底在内存中是如何运行的呢?以上个程序为例,进行图解说明:

    多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈。

    当执行线程的任务结束了,线程自动在栈内存中释放了。但是当所有的执行线程都结束了,那么进程就结束了。

    1.2 Thread类

    在上一天内容中我们已经可以完成最基本的线程开启,那么在我们完成操作过程中用到了 java.lang.Thread 类,

    API中该类中定义了有关线程的一些方法,具体如下:

    构造方法

    • public Thread() :分配一个新的线程对象。
    • public Thread(String name) :分配一个指定名字的新的线程对象。
    • public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
    • public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字

    常用方法

    • public String getName() :获取当前线程名称。
    • public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。
    • public void run() :此线程要执行的任务在此处定义代码。
    • public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
    • public static Thread currentThread() :返回对当前正在执行的线程对象的引用。

    知创建线程的方式总共有两种,一种是继承Thread类方式,一种是实现Runnable接口方式

    创建线程的方式

    1.第一种继承Thread类方式

    示例代码

    获取线程的名称

    Thread类

    public class MyThread extends Thread{
        @Override
        public void run(){
            // public String getName() :获取当前线程名称
            String name = getName();
            System.out.println(name);
            
            // Thread-0
            
            // public static Thread currentThread() :返回对当前正在执行的线程对象的引用。
            // 是一个静态方法,返回的是一个线程
            Thread t= Thread.currentThread();
            System.out.println(t);
            // Thread[Thread-0,5,main]
            
            System.out.println(t.getName());
            // Thread-0
            
            // 链式编程
            System.out.println(Thread.currentThread().getName());
        }
    }
    

    测试类

    public static void(String[] args){
        //创建Thread类中的子类对象
            MyThread mt = new MyThread();
            // 调用start方法,开启心的线程,执行run方法
            mt.start();
    
            new MyThread().start();
        }
    
    设置线程的名称

    Thread类

    /*
    设置线程的名称:
    	1.使用thread类中的getName方法
    		void setName(String name) 改变线程名称,使参数name相同
    	2.创建一个带参数的构造方法,参数传递线程的名称;调用父类的带参数的构造方法,把线程名称传递给父类,让父类(Thread)给子线程起一个名字
    		Thread(String name)分配新的 Thread 对象
    */
    public class MyThread extends Thread{
        @Oerride
        public void run(){
            System.out.println(Thread.currentThread().getName());
        }
        public MyThread(){}
        public MyThread(String name){
            // 把线程名称传递给父类,让父类(Thread)给子线程起一个名字
            super(name);
        }
    }
    
    

    测试类

    public static void main(String[] args){
        // 开启多线程
        MyThread mt = new MyThread();
        mt.setName("二郎神");
        mt.start();
        
        // 开启多线程
        new MyThrad("哮天犬").start();
    }
    
    程序暂停指定的时间
    /*
    public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。 
    */
    public static void main(String[] args){
        for(int i = 1;i<=60;i++){
            System.out.println(i);
        }
        // 使用thread类中的sleep方法让程序睡眠一分钟
        try{
    		Thread.sleep(1000);
        }catch(InterruptedException e){
            e.printStackTreace();
        }
    }
    

    1.3 创建线程方式二

    2.第二种实现Runnable接口方式

    java.lang.Runnable

    ​ Runnable 接口应该由那些打算通过某一线程执行其 实例的类来实现。类必须定义一个称为 run 的无参方法

    java.lang.Thread类的构造方法

    ​ Thread(Runnable target) 分配新的Treach对象

    ​ Thread(Runnable target,String name) 分配新的Treach对象

    实现步骤:

    1. 创建一个Runnable接口的实现类
    2. 在实现类中重写Runnable接口中的run方法,设置线程任务
    3. 创建一个Runnable接口的实现类对象
    4. 创建Thread类对象,构造方法中传递Runnable接口的实现类对象
    5. 调用Thread类中的start方法,开启新的线程

    示例代码

    // 创建一个Runnable接口的实现类
    public class RunnableImpl implements Runnable{
       //  在实现类中重写Runnable接口中的run方法,设置线程任务
        @Override
        public void run(){
            for(int i = 0;i<6;i++){
                System.out.prinln(Thread.currentThrad().getName()+"---"+i);
            }
        }
    }
    

    测试类

    public class Demo01Runnable {
        public static void main(String[] args) {
            // 创建一个Runnable接口的实现类对象
        	Runnable run = new RunnableImpl();
            // 创建Thread类对象,构造方法中传递Runnable接口的实现类对象
            Thread t = new Tread(run);
            // 调用Thread类中的start方法,开启新的线程
            t.start();
    
            for (int i = 0; i < 6; i++) {
                System.out.println(Thread.currentThread().getName() + "---" + i);
            }
        }
        // 运行结果
        main---0
    main---1
    main---2
    main---3
    main---4
    main---5
    Thread-0---0
    Thread-0---1
    Thread-0---2
    Thread-0---3
    Thread-0---4
    Thread-0---5
    

    1.4 Thread和Runnable的区别

    如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。

    总结:

    实现Runnable接口比继承Thread类所具有的优势:

    1. 适合多个相同的程序代码的线程去共享同一个资源。
    2. 可以避免java中的单继承的局限性。
    3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
    4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。

    扩充:在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用 java命令执行一个类的时候,实际上都会启动一个JVM,每一个JVM其实在就是在操作系统中启动了一个进程

    1.5 匿名内部类方式实现线程的创建

    匿名:没有名字

    内部类:写在其他类内部的类

    匿名内部类的作用:简化代码

    ​ 把子类继承父类,重写父类的方法,创建子类对象合为一步完成

    ​ 把实现类实现类接口,重写接口中的方法,创建实现类对象合为一步完成

    匿名内部类最终产物:子类/实现类对象,而这个类没有名字

    public static void main(String[] args) {
            // 线程的父类是Thread
            // new MyThread().start();
            new Thread(){
                @Override
                public void run() {
                    for (int i = 0; i < 8; i++) {
                        System.out.println(Thread.currentThread().getName()+"--"+"coll");
                    }
                }
            }.start();
    
            // 线程接口Runnable
            // Runnable r = new Runnable();多态
            Runnable r = new Runnable(){
                // 重写run方法,设置线程任务
    
                @Override
                public void run() {
                    for (int i = 0; i < 8; i++) {
                        System.out.println(Thread.currentThread().getName()+"--"+"luncry");
                    }
                }
            };
            new Thread(r).start();
    
            // 简化接口的方式
            new Thread(new Runnable(){
                // 重写run方法,设置线程任务
    
                @Override
                public void run() {
                    for (int i = 0; i < 8; i++) {
                        System.out.println(Thread.currentThread().getName()+"--"+"完事");
                    }
                }
            }).start();
        }
    }
    

  • 相关阅读:
    CentOS查看CPU信息、位数、多核信息
    Linux常用命令大全
    chmod命令详细用法
    tar命令的详细解释
    yum和rpm命令详解
    LeetCode 241. Different Ways to Add Parentheses
    LeetCode 139. Word Break
    LeetCode 201. Bitwise AND of Numbers Range
    LeetCode 486. Predict the Winner
    LeetCode 17. Letter Combinations of a Phone Number
  • 原文地址:https://www.cnblogs.com/anke-z/p/12604275.html
Copyright © 2011-2022 走看看