1、进程:正在进行的程序
2、线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。 线程=======路
一般分为单线程和多线程,单线程就是执行完一个再去执行下一个,多线程是执行一个的同时可以执行下一个,多个线程同时交叉执行。
分时调度是按照cpu的时间划分,抢占式调度是随机分配时间。
抢占式调度详解,他是一个多进程并发运行,看着像是“同时运行”但是确实基于cpu使用抢占式调度模式在多线程中高速切换,cpu一时刻只能执行一个线程,但是多个线程并发就让我们感觉到多个同时运行啦。
多线程程序并不能提高程序的运行速度,但是能够提高效率。
就算是一个多线程他仍旧是有一个主线程的,那就是我们压栈的main。
jvm启动后,必然有一个执行路径(线程)从main方法开始的,一直执行到main方法结束,这个线程在java中称之为主线程。
因为本身main方法是从上往下执行,如果一个方法过长,或者某一个出错下面的不能执行。但是有了多线程,就不担心这个啦。
如何执行多线程,有一个单独的类,叫做 Thread类
构造方法:
这个构造方法Thread是为了分配多线程而产生,因为也是类,根据类的操作方式,类名 名称 = new 类型();new的类就是新分配一条线程。
常用方法:
其中,run是线程任务。
两种创建线程方式:
1、首先创建一个类,继承Thread类,作为子类,然后重写run方法,在run方法里面写执行内容,并在main里面new Thread ,调用start方法开启线程。
创建线程的步骤:
- 1 定义一个类继承Thread。
- 2 重写run方法。
- 3 创建子类对象,就是创建线程对象。
- 4 调用start方法,开启线程并让线程执行,同时还会告诉jvm去调用run方法。
需要注意的是,每一次创建一个线程对象就会在栈里面new一个新栈区,从而让cpu切换调度两个或多个线程。
并且我们创建了多个线程对象,Thread线程类为了让我们好区分各个线程,创造两个方法来获取线程名称。
因为新建类里面直接继承了Thread类,所以在Thread里面可以直接调取类里面方法getName。并且直接在main里面new对象来获取myThread类的地址,通过start来开启线程。
但是mian这个正在执行的方法并不知道自己是线程中的主线程,需要先通过currentThread方法来获取到目前正在执行的main,并且用Thread类 的变量名来接收,从而调取此类下的所有方法,m.getName();
新建类继承Thread public class MyThread extends Thread{ //重写run方法,即开启线程任务 public void run() { for(int i=0;i<50;i++){ System.out.println(getName()+":"+i); } } main方法开启线程,并书写主线程 for public static void main(String[] args) {
//普通方法调取run,还是单线程,先走run
MyThread mt=new MyThread();
//不能调取run
//mt.run();
//开启线程
mt.start();
MyThread mt1=new MyThread();//一个代表一个线程
mt1.start();
Thread m=Thread.currentThread();
//主线程 main
for(int i=0;i<50;i++){
System.out.println(m.getName()+"---"+i);
}
}
}
第二种开启线程方式--Runnable接口
实现步骤:自定义类实现Runnable接口,覆盖掉接口中的run方法,然后测试类中创建Thread对象,将子类Runnable子类线程对象作为参数传入Thread构造函数中,开启start方法。
- 1、定义类实现Runnable接口。
- 2、覆盖接口中的run方法。。
- 3、创建Thread类的对象
- 4、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。
- 5、调用Thread类的start方法开启线程。
package com.oracle.demo1; public class MyRunable implements Runnable { public void run() { for(int i=0;i<50;i++){ //匿名对象直接静态获取调取父类方法.getName System.out.println(Thread.currentThread().getName()+":"+i); } } } 测试类: public static void main(String[] args) { //创建线程任务对象 MyRunable mr=new MyRunable(); MyRunable mr1=new MyRunable(); //创建Thread对象 将自定义线程对象作为参数传递到Threa构造方法中。 Thread th=new Thread(mr); Thread th1=new Thread(mr1); //开启线程 th.start(); th1.start(); for( int i=0;i<50;i++){ System.out.println(Thread.currentThread().getName()+"--"+i); }
ps:使用Runnable的好处,首先是避免了java单继承的规则,因为Runnable是接口,第二,将线程分为了线程对象和线程任务,更符合面向对象的原理,第三,避免继承Thread的耦合性,让程序更为灵活,实现解耦。
第三种开启方式----匿名内部类与多线程。
匿名内部类与多线程的好处是,利用多态的向上转型,父类对象指向子类对象,匿名内部类自有的重写父类,创建子类对象,从而避免了创建一个自定义类,直接在主线程main里面实现从上往下的多线程效果。
//匿名内部类 创建的是一个Runnable方法 //这里的Runnable是一个接口不能new,所以new的不是对象,而匿名对象new 的是父类或者接口,Runnable r接收的便是它的重写的子类。 //Runnable r的接口来接收它的Runnable实现类 Runnable r=new Runnable(){ public void run() { System.out.println("我是匿名线程任务"); } }; Thread th2=new Thread(r); th2.start();