2018-08-25多线程Thread类+Runnable接口+线程的6种状态

 

多线程:

进程:进程指正在运行的程序;确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能(进入内存运行的程序成为进程)!

 

线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程!一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序(线程是执行单元,一个进程可以包括多个线程,一个程序可以有多个进程)!

 

单线程程序:若有多个任务只能依次执行(这个任务执行完毕,下一个任务开始执行)!如:去网吧上网,网吧只能让一个人上网,当这个人下机后,下一个人才能上网(这个任务进站执行完毕,弹栈之后,下一个任务才可以执行)!

多线程程序:若有多个任务可以同时执行!如:去网吧上网,网吧能够让多个人同时上网(一个线程建一个栈,多个栈内的任务同时执行,Main方法也是一个栈)!

//八核十六线程的CPU:一个核心有16个线程!

程序运行原理:

分时调度:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间(比如360安全卫士有3个功能:杀毒,电脑清理,系统修复,这三个功能会被JVM分配1微秒的时间片,轮流执行1微秒,看起来像是同时执行,但实际并不是)!

抢占式调度:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(称为线程的随机性),Java使用的为抢占式调度(Java采用抢占式调度)!

//可以通过Windwos系统的任务管理器(Ctrl键+Shift键+Esc键调出)设置进程的优先级:

实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换(分配时间片)!对于CPU的一个核而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻运行,其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的使用率更高(单核单线程只能这个任务执行完毕再执行下一个任务,现在多核多线程可以多个任务同时执行,节省时间)!

主线程:Main方法就是主线程!

 

JVM启动后必然有一个执行路径(线程)从main方法开始的,一直执行到main方法结束,这个线程在Java中称之为主线程!当程序的主线程执行时,如果遇到了循环而导致程序在指定位置停留时间过长,则无法马上执行下面的程序,需要等待循环结束后能够执行!

 

Thread类:

//第2个构造方法的String name是用来指定线程的名称!

 

常用方法:

//start()方法会调用继承自Thread类的子类重写之后的run()方法(如果直接使用Thread子类的对象调用重写后的run()方法,不会开启线程,就是普通的对象调用方法,所以想要开启线程用start()方法)!

//sleep()方法:让该线程休眠,即结束进程!

 

强调:

Thread t1 = new Thread();

t1.start();

//这样做没有错,但是该start()调用的是Thread类中的run()方法,而这个run()方法没有做什么事情,更重要的是这个run方法中并没有定义我们需要让线程执行的代码!

 

每一个线程都有一个独立的内存中的栈空间,所以可以实现并发执行(又要牵扯到管理高并发的问题):

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

 

//获取当前执行的线程的对象或名称:

//由于这个方法是静态的,所以可以类名.方法调用!

 

课堂示例代码:

package com.oracle.duoxiancheng;
public class Demo01 {
    public static void main(String[] args) {
        //thread新建的线程,和Main方法都是线程,Main方法是主线程,在内存中享有独立的栈空间:
        //新建第一个线程:
        MyThread mt1=new MyThread();
        //开启该线程(调用run()方法):
        mt1.start();
        //新建第二一个线程:
        MyThread mt2=new MyThread();
        //开启该线程(调用run()方法):
        mt2.start();
        for(int i=0;i<1000;++i){
            System.out.println("main……"+i);
        }
        System.out.println("程序结束了!");
        //查看main方法线程名字:
        System.out.println(Thread.currentThread().getName());
    }
}

package com.oracle.duoxiancheng;
public class MyThread extends Thread {
    public void run() {
        System.out.println(super.getName());
        //重写run方法,把并发执行的代码放在里面,run方法不需要程序员调用,线程对象的.start()方法:
        for(int j=0;j<1000;++j){
            System.out.println("run……"+j);
        }
    }
}

创建线程方式—实现Runnable接口:

创建线程的另一种方法是声明实现 Runnable 接口的类!该类然后实现 run 方法,然后创建Runnable的子类对象,传入到某个线程的构造方法中,开启线程!

//好处:把任务体(Runnable中的run()方法)跟创建线程和开启线程(Thread和start()方法)分离开了!

Thread类的构造方法:

//可以传入一个Runnable对象,以及一个线程名字!

 

创建线程的步骤:

1;定义类实现Runnable接口!

2;覆盖接口中的run方法!

3;创建Thread类的对象!

4;将Runnable接口的子类对象作为参数传递给Thread类的构造函数!

5;调用Thread类的start()方法开启线程!

 

通过Runnable和Thread方法 来实现创建开启线程的好处:

①    实现Runnable接口,避免了继承Thread类的单继承局限性!覆盖Runnable接口中的run方法,将线程任务代码定义到run方法中!

②    更加符合面向对象思想,实现了线程任务和线程对象的解耦!

//下方TIMED_WAITING应该是WAITING,其中Wait()和Notify()是属于Object类!

 

示例代码:

package com.oracle.duoxiancheng;
public class Demo01 {
    public static void main(String[] args) {
        //thread新建的线程,和Main方法都是线程,Main方法是主线程,在内存中享有独立的栈空间:
        //新建第一个线程,设置线程名称方法②,MyThread重写了Thread的构造方法:
        MyThread mt1=new MyThread("诸葛鬼才");
        //开启该线程(调用run()方法):
        mt1.start();
        //新建第二一个线程:
        MyThread mt2=new MyThread();
        //设置线程名称方法①:
        mt2.setName("蔡文姬");
        //开启该线程(调用run()方法):
        mt2.start();
        /*for(int i=0;i<1000;++i){
            System.out.println("main……"+i);
        }*/
        System.out.println("程序结束了!");
        //查看main方法线程名字:
        System.out.println(Thread.currentThread().getName());
    }
}

package com.oracle.duoxiancheng;
public class MyThread extends Thread {
    public MyThread(String getName){
        super(getName);
    }
    public MyThread(){
        
    }
    public void run() {
        System.out.println(super.getName());
        //重写run方法,把并发执行的代码放在里面,run方法不需要程序员调用,线程对象的.start()方法:
        /*for(int j=0;j<1000;++j){
            System.out.println("run……"+j);
        }*/
    }
}

通过Runnable接口和Thread对象开启线程:
package com.oracle.duoxiancheng;
public class Demo02 {
    public static void main(String[] args) throws InterruptedException {
        //runnable实现类任务的编写:
        MyRunnable mr=new MyRunnable();
        //Thread负责创建线程并开启线程
        Thread th1=new Thread(mr);
        th1.start();
        for(int i=0;i<50;++i){
            //休眠可以自己醒:
            Thread.sleep(5000);
            System.out.println("main……"+i);
        }
    }
}

package com.oracle.duoxiancheng;
public class MyRunnable implements Runnable {
    public void run(){
        for(int i=0;i<50;++i){
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("这个是run()方法内的……"+i);
        }
    }
}

匿名对象创建并开启线程:
package com.oracle.duoxiancheng;
public class Demo03 {
    public static void main(String[] args) {
        //匿名内部类,下面的new Thread是Thread的子类,只不过没有名字:
        new Thread(){
            public void run(){
                for(int i=0;i<50;++i){
                    System.out.println("Run……"+i);
                }
            }
        }.start();
        
        //匿名内部类,匿名new Thread对象里面放一个匿名内部类(Runnable的子类):
        new Thread(new Runnable(){
            public void run(){
                for(int i=0;i<50;++i){
                    System.out.println("Run……"+i);
                }
            }
        }).start();
        
        //匿名内部类,new Runnable(){}部分是Runable的子类,前面的Runnable ra=是多态,传入Thread子类对象的构造方法:
        Runnable ra=new Runnable(){
            public void run(){
                for(int i=0;i<50;++i){
                    System.out.println("Run……"+i);
                }
            }
        };
        Thread ta=new Thread(ra);
    }
}

 

posted on 2018-08-25 16:17  Postgre叮当牛i  阅读(180)  评论(0编辑  收藏  举报

导航