【214天】黑马程序员27天视频学习笔记【Day24-上】

叨逼叨两句

  1. 哈哈哈哈哈哈哈哈哈哈哈哈
  2. 今天了结了一个心结,瞬间整个人的时不时涌现的恐慌情绪都解除了,没了这个后顾之忧分心,瞬间学习专注力爆表啊!!!果然,我只要没有特别大的让我分心的琐事,专注一件事的能力就是很强很强很强!!!当年读书时总能后期大爆发迎头赶上,看来也不是没有原因的。
  3. 我记忆力不算特别强,也就比均值高一点,80分样子,但是我的专注力极强,我有信心自己是那前5%的人。
  4. 今天学的内容我感觉特别high,一方面老师讲的好,另一方面是这些内容涉及计算机底层原理,让我在计算机这个黑箱上戳了个小洞,满足了我的好奇心。
  5. 之后项目之余,我要好好看看这些底层原理的书,就看着玩,不求甚解。

24-01:多线程的引入

  1. 什么是线程

    • 线程是程序执行的一条路径,一个进程中可以包含多条线程。
    • 多线程并发执行可以提高程序的效率,可以同时完成多项工作。
  2. 多线程原理

24-02:多线程的并行与并发

  1. 并行:两个任务同时进行【需要多个CPU】
  2. 并发:两个任务都请求CPU处理,而CPU同一时间只能接受一个任务,就把这两个任务安排轮流进行,由于CPU切换时间极短,处理速度极快,会让人感觉两个人任务同时在运行。

24-03:Java程序运行原理和JVM的启动是多线程的吗?

  1. Java程序的运行原理

    • Java命令会启动Java虚拟机。启动JVM就等于启动了一个应用程序,也就是启动了一个进程,该进程会自动启动一个“主线程”,然后主线程去调用某个类的main方法。
  2. JVM的启动是多线程的吗?

    • 是,JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。
    package com.test.demo001;
    
    public class Demo015 {
        public static void main(String[] args) {
            for(int i = 0; i < 10000000; i++){
                new Demo();
            }
        }
    }
    
    class Demo {
        public void finalize(){
            System.out.println("垃圾已经回收");
        }
    }

24-(04-06):多线程程序实现的两种方法

方法1

  1. 继承Thread

    1. 定义一个类继承Thread
    2. 重现run方法
    3. 把新线程要做的事写在run方法中
    4. 创建线程对象
    5. 开启新线程,内部会自动执行run方法【start就想百米赛跑的发令枪,一开枪,各个线程就像各个赛道的运动员一样开始跑了(CPU轮流处理)】
package com.test.demo001;

public class Demo015 {
    public static void main(String[] args) {
        Demo d = new Demo();
        d.start();
        
        for (int i = 0; i < 1000; i++) {
            System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
        }    
    }
}

class Demo extends Thread{
    public void run(){
        for(int i = 0; i < 1000; i++){
            System.out.println("bbbbbb");
        }
    }
}

方法2

  1. 实现Runnable

    • 定义类实现Runnable接口
    • 实现run方法
    • 把新线程要做的事写在run方法中
    • 创建自定义的Runnable的子类对象
    • 创建Thread对象,传入Runnable
    • 调用start()开启新线程,内部会自动调用Runnable的run()方法
package com.test.demo001;

public class Demo015{
    public static void main(String[] args) {
        Demo d = new Demo();
        Thread t = new Thread(d);
        t.start();
        
        for(int i = 0; i < 1000; i++){
            System.out.println("bbb");
        }
    }
}

class Demo implements Runnable{
    public void run(){
        for(int i = 0; i < 1000; i++){
            System.out.println("aaaaaaaaaaaaaa");
        }
    }
}
  1. 实现Runnable的原理

    根据源码可知:

    1. Thread有一个构造函数,接收Runnable类型的参数
    2. 该构造函数接收参数后,最终这个参数会传给Thead对象的一个Runnable类型的成员变量(变量名为 target)。
    3. 当你用Thread对象调用start方法时,它会调用Thread对象的run方法
    4. 当Thread对象的run方法被调用时,它将执行target的run方法,而这个target的run方法,就是你那个实现了Runnable的类的run方法。

24-07:两种方式的区别

  1. 查看源码的区别:

    1. 继承Thread:由于子类重写了Thread类的run(),当调用start()时,直接找子类的run()方法。
    2. 实现Runnable:构造函数中传入了Runnable的引用,成员变量记住了它,start()调用run()方法时,内部判断成员变量Runnable的引用若不为null,它就将执行实现了Runnable接口的这个子类的run()方法。
  2. 继承Thread【开发推荐】

    • 优点:可以直接使用Thread类中的方法,代码简单
    • 缺点 :如果已经有了父类,就不能用这种方法
  3. 实现Runnable接口

    • 优点:即使自己定义的线程有了父类也木有关系,依然可实现Runnable接口。
    • 缺点:不能直接使用Thread中的方法,需要先获取到线程对象后,才能得到Thread的方法,代码复杂。

24-08:匿名内部类实现线程的两种方式

  1. 继承Thread类

        package com.test.demo001;
    
    public class Demo015{
        public static void main(String[] args) {
            new Thread(){
                public void run(){
                    for(int i = 0; i < 1000; i++){
                        System.out.println("bbbbbbbbbbbbb");
                    }
                }
            }.start();
            
            for(int i = 0; i < 1000; i++){
                System.out.println("aaaa");
            }
            
            
        }
    }
    
  2. 实现Runnable接口

    package com.test.demo001;
    
    public class Demo015{
        public static void main(String[] args) {
            new Thread(
                    new Runnable(){
                        public void run(){
                            for(int i = 0; i < 1000; i++){
                                System.out.println("bbbbbbbbbbbb");
                            }
                        }
                    }
            ).start();
            
            for(int i = 0; i < 1000; i++){
                System.out.println("aaaa");
            }
            
            
        }
    }

24-09:获取名字和设置名字

  1. 获取名字

    • 通过getName()方法获取线程对象的名字【Thread类有默认的名字,但你也可以自己修改】
        package com.test.demo001;
    
    public class Demo015{
        public static void main(String[] args) {
            new Thread(){
                public void run(){
                    for(int i = 0; i < 1000; i++){
                        System.out.println(this.getName()+".......bbbbbbbbbbbbbb");
                    }
                }
            }.start();
            
            new Thread(){
                public void run(){
                    for(int i = 0; i < 1000; i++){
                        System.out.println(this.getName()+".......aa");
                    }
                }
            }.start();
        }
    }
    
  2. 设置名字

    • 通过构造函数可以传入String类型的名字
    package com.test.demo001;
    
    public class Demo015{
        public static void main(String[] args) {
            new Thread("NB"){
                public void run(){
                    for(int i = 0; i < 1000; i++){
                        System.out.println(this.getName() + ".......bbbbbbbbbbbbbb");
                    }
                }
            }.start();
            
            new Thread("SB"){
                public void run(){
                    for(int i = 0; i < 1000; i++){
                        System.out.println(this.getName() + ".......aa");
                    }
                }
            }.start();
            
            
        }
    }
    • 通过setName(String)方法可设置线程对象的名字
    package com.test.demo001;
    
    public class Demo015{
        public static void main(String[] args) {
            new Thread(){
                public void run(){
                    this.setName("NB");
                    for(int i = 0; i < 1000; i++){
                        System.out.println(this.getName() + ".......bbbbbbbbbbbbbb");
                    }
                }
            }.start();
            
            new Thread(){
                public void run(){
                    this.setName("SB");
                    for(int i = 0; i < 1000; i++){
                        System.out.println(this.getName() + ".......aa");
                    }
                }
            }.start();
            
            
        }
    }
    
        package com.test.demo001;
    
    public class Demo015{
        public static void main(String[] args) {
            Thread t1 = new Thread(){
                public void run(){
                    for(int i = 0; i < 1000; i++){
                        System.out.println(this.getName() + ".......bbbbbbbbbbbbbb");
                    }
                }
            };
            
            Thread t2 = new Thread(){
                public void run(){
                    for(int i = 0; i < 1000; i++){
                        System.out.println(this.getName() + ".......aa");
                    }
                }
            };
            
            t1.setName("NB");
            t2.setName("SB");
            t1.start();
            t2.start();
            
            
            
        }
    }
    

24-10:获取当前线程

Thread.currentThread()

  1. 继承Thread的方式不用使用这个方法,实现Runnable接口的方式需要使用。
package com.test.demo001;

public class Demo015{
    public static void main(String[] args) {
        new Thread(){
            public void run(){
                for(int i = 0; i < 1000; i++){
                    System.out.println(this.getName() + ".......bbbbbbbbbbbbbb");
                }
            }
        }.start();
        
        new Thread(
                new Runnable(){
                    public void run(){
                        for(int i = 0; i < 1000; i++){
                            System.out.println(Thread.currentThread().getName()+ "....aa");
                        }
                    }
                }
                
        ).start();
            
    }
}
  1. 主线程也能这样获取
package com.test.demo001;

public class Demo015{
    public static void main(String[] args) {
        //Thread.currentThread().setName("NB");
        System.out.println(Thread.currentThread().getName());
    }
}

24-11:休眠线程

  1. sleep()
  2. 1秒=1000毫秒=1000*1000微秒=1000*1000*1000纳秒
package com.test.demo001;

public class Demo015{
    public static void main(String[] args) throws InterruptedException {
        for(int i = 10; i >= 0; i--){
            Thread.sleep(1000);
            System.out.println(i);
        }
    }
}
  1. CPU遇见一个sleep()就会先不执行这一个,而改去执行另一个,直到sleep的时间结束。【之后还会学一个wait方法,这个是没有时间限制的】
package com.test.demo001;

public class Demo015{
    public static void main(String[] args) throws InterruptedException {
        new Thread(){
            public void run(){
                for (int i = 0; i < 1000; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(".......aaaaaaaaaaaa");
                }
            }
        }.start();
        
        new Thread(){
            public void run(){
                for (int i = 0; i < 1000; i++) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(".......bb");
                }
            }
        }.start();
        
        
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值