06 多线程 01多线程概述 + 堆和方法区共享内存 + 分析程序存在几个线程 + 实现线程的两种方式 + 获取当前线程对象

1、多线程概述

  /*
  * 1、什么是进程?什么是线程?
  *     进程是一个应用程序(1个进程是一个软件)
  *     线程是一个进程中的执行场景(执行单元)
  *     一个进程可以启动多个线程
  * 2、对于java程序来说,从dos窗口中输入:
  *     java helloWord 回车之后
  *     会先启动JVM,,而JVM就是一个进程
  *     同时再启动一个主线程调用main方法
  *     同时再启动一个垃圾回收线程负责看护,回收垃圾
  *     最起码,现在的java程序中至少有两个线程并发
  *     一个是垃圾回收线程,一个是执行main方法的主线程
  * 3、进程和线程是什么关系?
  *     阿里巴巴:进程
  *         童文红:阿里巴巴的一个线程
  *         马云:阿里巴巴的一个线程
  *     京东:进程
  *         强东:京东的一个线程
  *         奶茶:京东的一个线程
  *     进程可以看做现实生活中的公司
  *     线程可以看做公司的某个员工
  *     注意:
  *         进程A和进程B内存独立不共享资源
  *         线程A和线程B呢?
  *             线程A和线程B,堆内存和方法区内存共享
  *             当时栈内独立,一个线程一个栈
  *             假设启动10个线程,会有10个栈,每个栈和每个栈之间,互不干扰,各自执行各自的,这就是多线程并发
  *         火车站:进程
  *         火车站窗口:一个售票窗口是一个线程   再每个售票窗口,你不等我,我不等你,提高效率
  *     4、思考一个问题?
  *         使用了多线程机制,main方法结束,是不是有可能程序结束
  *         main方法结束,只是主线程结束了,其他的栈(线程)可能还在压栈弹栈
  * */

2、堆和方法区共享内存

 

 /*
        * 1、分析一个问题,对于单核的CPU来说,真的可以做到真正的多线程并发吗?
        * 对于多核的CPU电脑来说,真正的多线程并发没有问题。4核CPU表示同一个时间点上,可以真正的4个进程并发执行
        *   什么是真正的多线程并发?
        *   t1线程执行t1的
        *   t2线程执行t2的
        *   t1不会影响t2,t2也不会影响t1,这叫真正的多线程并发
        *   单核的CPU只有一个大脑:
        *       能够做到真正的多线程并发,但是可以做到给人一种“多线程并发”的感觉
        *       对于单核的CPU来说,在某个时间点上实际上只能处理一件事情,但是由于CPU的执行速度极快,多个线程之间频繁切换执行,跟人来的感觉就是,
        *       多个事情同时在做         
        *       线程A:播放音乐
        *       线程B:运行魔兽游戏
        *       线程A和线程B频繁切换,给人的感觉就是一会儿播放音乐,一会儿运行游戏
        *   电影院采用胶卷播放电影,一个胶卷一个胶卷播放速度达到一定程度之后
        *   人类的眼睛产生了错觉,感觉是动画的,这说明人类的反应速度很慢,就像一根钢针扎到手上,到最终感觉到疼,这个过程是需要“很长的”时间,在这个期间计算机可以
        *   进行亿万次的循环,所以计算机的执行速度很快
        * */

3、分析程序存在几个线程

/*
* 大家分析有几个线程?
*   1、一个线程,垃圾回收器
*   2、只有一个主线程,没有启动分支栈,没有启动分支栈,一个栈中,自上而下的顺序执行
* */

public class HashSet01 {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        System.out.println("main begin");
        m1();
        System.out.println("main over");
    }
    private static void m1(){
        System.out.println("m1 begin");
        m2();
        System.out.println("m2 over");
    }
    private static void m2(){
        System.out.println("m2 begin");
        m3();
        System.out.println("m2 over");
    }
     private static void m3(){
         System.out.println("m3 execute");
     }

 4、实现线程的两种方式

/*
* 实现线程的第一种方式:
*   编写一个类,直接继承java.lang.Thread  重写run方法
*   怎么创建线程对象?new就可以了
*   怎么启动线程呢?调用线程对象的start方法
* 注意:亘古不变的道理:方法体中的代码永远都是自上而下的顺序依次逐行执行
* 以下程序的输出结果有这样的特点:
*   有先有后
*   有多有少
* 第一种方式:
*   定义线程类
*   public class MyTread extends Thread{
*   public void run(){
*
*   }
*   //创建线程对象
*   MyThread my = new MyThread();
*   //启动线程
*   my.start();
* 第二种方式:编写一个类,实现java.lang.Runnable接口,实现run方法
*   //定义一个可运行的类
*   public  class MyRunnable implements Runnable {
*   public  void run(){
* }
* }
* //创建线程对象
* Thread t = new Thread(new MyRunnable());
* //启动线程
* t.start()
* }
* 注意:第二种方式实现接口比较常用,因为一个类实现了接口,它还可以继承其他的类,更灵活
*
*
*
*
*
* */
public class ThreadTest {
    public static void main(String[] args) {
        //这里是main方法,这里的代码属于主线程,在主栈中运行
        //新建一个分支线程对象
        MyThread myThread = new MyThread();
       // myThread.run();  //不会启动线程,不会分配新的分支栈(这种方式是分支线程)
        //启动线程
        //start()方法的作用是:启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码任务完成之后,瞬间就结束了
        //这段代码的任务只是为了开启一个新的栈空间,只要新的栈空间开辟出来,start()方法就结束了,线程就启动成功了
        //启动成功的线程会自动调用run方法,并且run方法在分支栈的栈底部(压栈)
        //run方法在分支栈的底部,main方法在主栈的栈底部,run和main是平级的
        myThread.start();   //开辟分支栈

        //这里的代码还是运行在主线程中
        for(int i = 0; i < 1000; i++){
            System.out.println("主线程----》" + i);
        }

        //创建线程对象,采用匿名内部类方式
        //这是通过一个没有名字的类,new出来的对象
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i = 0; i < 100; i++){
                    System.out.println("分支线程》》》》》》》》" + i);
                }
            }
        });
        //启动线程
        t.start();
        for(int i  = 0; i < 100; i++){
            System.out.println("主线程》》》》》》》》》》》" + i);
        }


    }
}

class MyThread extends Thread{
    public void run(){
        //编写程序,这段程序运行在分支线程中(分支栈)
        for(int i = 0; i < 1000; i++){
            System.out.println("分支线程-----》" + i);
        }
    }
}
/**
 * Created by Mike
 */
public class ThreadTest01 {

    /*
    *
    * 实现java.lang.Runnable接口
    * */


    public static void main(String[] args) {
        //创建一个可运行的对象
        MyRunnnable r = new MyRunnnable();
        //将可运行的对象封装为一个线程对象
        Thread t = new Thread(r);
        //启动线程
        t.start();

        //主线程
        for(int i = 0; i < 1000; i++){
            System.out.println("主线程》》》》》》》》》》" + i);
        }

    }
}

// 这并不是一个线程,而是一个可运行的类,它还不是一个线程
class MyRunnnable implements  Runnable{


    @Override
    public void run() {
        for(int i = 0; i < 1000; i++){
            System.out.println("分支线程》》》》》》》》》》" + i);
        }
    }
}

5、获取当前线程对象

 /*
    *
    * 1、怎么获取当前线程对象?
    *   static Thread currentThread()
    * 2、获取线程对象的名字
    *   String name = 线程对象.getName()
    * 3、修改线程对象的名字
    *   "线程对象".setName(newName)
    * 4、当线程没有设置名字的时候,默认名字有什么规律
    *   Thread-0
    *   Thread-1
    * */
 //创建线程对象
        MyThread t = new MyThread();
        //设置线程名字
        t.setName("tttt");
        //获取线程名字
        String tName = t.getName();
        System.out.println(tName);   //Thread 0

        //启动线程
        t.start();
        System.out.println();
       for(int i = 0; i < 1000; i++){
            //currentThread 就是当前线程对象,出现在哪就是当前线程对象
            Thread currentThread = Thread.currentThread();
            System.out.println("分支线程》》》》》》》》》》" + i);
        }

6、终断线程的睡眠

 public static void main(String[] args) {
        /*
        * 关于线程的sleep方法
        *   static  void  sleep(long millis)
        *   1、静态方法:Thread.sleep(100);
        *   2、参数是毫秒
        *   3、作用:让当前线程进入休眠,进入“阻塞状态”,放弃占有CPU时间片,让给其他线程使用
        *           这行代码出现在A线程中,A线程就会进入休眠
        *           这行代码出现在B线程中,B线程就会进入休眠
        *   4、Thread.sleep()方法,可以做到这种效果,间隔特定的时间,去执行一段特定的代码,每隔多久执行一次
        *   5、sleep睡眠太久了,如果希望半道上醒来,要终止线程的睡眠,而不是中断线程的执行 "线程对象".interrupt()
        *
        *
        * */
        //让当前线程进入休眠,睡眠5秒
        //当前线程是主线程
        Thread t = new Thread(new MyRunnnable());
        t.start();
        t.interrupt();
        System.out.println(Thread.currentThread().getName());
    }
}

// 这并不是一个线程,而是一个可运行的类,它还不是一个线程
class MyRunnnable implements  Runnable{

    //重点:run()当中的异常不能throws,只能try   catch
    //因为run()方法在父类中没有抛出任何异常,子类不能比父类抛出更多的异常


    @Override
    public void run() {
        System.out.println("分支线程》》》》》》》》》》");
        try {
            Thread.sleep(1000 * 60 * 60);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //终断t线程的睡眠(这种终断睡眠的方式,依靠了java的异常处理机制
        Thread.interrupted();
        System.out.println("线程终断");
    }
}

 

posted @ 2022-01-26 16:06  zhustarstar  阅读(65)  评论(0编辑  收藏  举报