多线程(1)

多线程运行原理

简单来说,多线程就是在程序执行的时候,再创建一个新的线程类,主程序执行的时候,是开辟了一条通往cpu的路径,而在主程序里面,有调用线程类的代码,也就是在执行的过程中,又开辟了一条新的通往cpu的路线。这也就是说,cpu在执行的时候就有了选择的余地,可以执行主线程,也可以执行线程类的内容,因为我们 无法控制cpu执行哪个,这也就是多线程的随机执行的原因。

Thread类

构造方法:

  1. public Thread() :分配一个新的线程对象。
  2. public Thread(String name) :分配一个指定名字的新的线程对象。
  3. public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
  4. public Thread(Runnable target,String name):分配一个带有指定目标新的现成对象并指定名字。

常用方法:

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

Thread和Runnable的区别
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
总结
实现Runnable接口比继承Thread类所具有的优势:

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

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

获取线程的名称

  1. 使用Thread类中的getName():String getName() 返回该线程的名称。
  2. 可以先获取到当前正在执行的线程,使用线程中的方法getName()获取线程名称:static Thread currentThread() 返回对当前正在执行线程对象的引用。

代码演示:
获取线程名称方法1

package day27;
import java.sql.SQLOutput;
public class xiancheng01 extends Thread{    
    @Override   
    public void run(){        
        String name = getName();        
        System.out.println(name);    
    }
}

获取线程名称方法2

package day27;
public class xiancheng03 extends Thread{    
    @Override    
    public void run(){        
        Thread t = Thread.currentThread();        
        System.out.println(t);    
    }
}

Thread类的常用方法sleep

public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)毫秒数结束之后,线程继续执行。

因为sleep方法本身是带有异常的,所以要使用try...catch方法解决。

代码演示:

package day27;
public class SleepDemo01 {    
    public static void main(String[] args) {        
        //模拟秒表        
        for (int i = 0; i < 60; i++) {            
            System.out.println(i);            
            //使用Thread类的sleep方法让程序睡眠1秒            
            try {                
                Thread.sleep(1000);            
            } catch (InterruptedException e) {                
                e.printStackTrace();            
            }        
        }    
    }
}

实现Runnable接口

创建多线程程序的第二种方式:实现Runnable接口
java.lang.Runnable
Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为run的无参数方法。
java.lang.Thread类的构造方法
Thread(Runnable target) 分配新的Thread对象。
Thread(Runnable target,String name) 分配新的Thread对象。

实现步骤:

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

代码演示:

package day27;
//创建一个Runnable接口的实现类
public class RunnableImpl implements Runnable{    
    @Override    
    public void run(){        
        for (int i = 0; i < 20; i++) {          
            System.out.println(Thread.currentThread().getName()+"-->"+i);        
        }    
    }
}
package day27;
public class RunnableDemo02 {    
    public static void main(String[] args) {        
        //创建一个Runnable实现类对象         
        RunnableImpl run = new RunnableImpl();        
        //创建Thread类对象,构造方法中传递Runnable接口的实现类对象        
        Thread t = new Thread(run);        
        //调用start方法,开启新的线程执行run方法        
        t.start();        
        for (int i = 0; i < 20; i++) {            
            System.out.println(Thread.currentThread().getName()+"-->"+i);        
        }    
    }
}

实现Runnable接口创建多线程程序的好处:

  1. 避免了单继承的局限性
    一个类智能集成一个类,类继承了Tread类就不能继承其他类。
    实现了Runnable接口,还可以继承其他的类,实现其他的接口。
  2. 增强了程序的扩展性,降低了程序的耦合性(解耦)
    实现Runnable接口的方式,把设置线程任务和开启新线程进行了奋力(解耦)
    实现类中,重写了run方法:用来设置线程任务。
    创建Thread类对象,调用start方法:用来开启新线程。

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

匿名:没有名字
内部类:卸载其他类内部的类

匿名内部类作用:简化代码
把子类继承父类,重写父类的方法,创建子类对象合一步完成
把实现类实现类接口,重写接口中的方法,创建实现类对象合成一步完成。

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

格式:
new 父类/接口(){
重复父类/接口中的方法
};

代码演示:

package day27;
public class Demo03 {    
    public static void main(String[] args) {        
        //线程的父类是Thread        
        // new Mythread().start();        
        new Thread(){            
            @Override            
            public void run(){                
                for (int i = 0; i < 20; i++){                    
                    System.out.println(Thread.currentThread().getName()+"-->"+"小明");                
                }            
            }        
        }.start();        
        //线程的接口Runnable        
        //Runnable r = new RunnableImpl(); //多态        
        Runnable r = new RunnableImpl(){            
            @Override            
            //重写run方法,设置线程任务            
            public void run(){                
                for (int i = 0; i < 20; i++) {                    
                    System.out.println(Thread.currentThread().getName()+"-->"+"君君");                
                }            
            }        
        };        
        new Thread(r).start();    
    }
}

并发与并行

并发:指两个或多个事件在同一个时间段内发生。
并行:指两个或多个事件在同一时刻发生(同时发生)。

线程与进程

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以同时运行多个进程;进程也是程序的一次执行过程,是系统运行程序的基本单位;系统运行一个程序即是一个进程从创建、运行到消亡的过程。
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。

简而言之,一个程序运行后至少有一个进程,一个进程中可以包含多个线程。

线程调度

  • 分时调度
    所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间。
  • 抢占式调度
    优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。

主线程

执行主方法(main方法)的线程就是主线程

单线程程序:java程序中只有一个线程。
执行从main方法开始,从上到下依次执行。

主线程概念:
JVM执行main方法,main方法会进入到栈内存
JVM会着操作系统开辟一条main方法桐乡cpu的执行路径,cpu就可以通过这个路径来执行main方法,这个路径就叫做main线程,也叫主线程。

posted @ 2020-10-28 23:42  小明-o3rr0r  阅读(69)  评论(0编辑  收藏  举报