线程:就是一个cup处理进程(应用程序)的一个通道,一个进程可以有多个线程,线程之前相互不干扰,线程属于进程中的一个执行单元。
多线程的优点:线程之间相互不干扰(因为每一个线程处在不能的栈之间),效率比较高。
java主线程:main方法中的线程。
- 创建多线程的方式有两种:
1·创建Thread类的子类
2·实现Runnable接口
Thread
- 创建Thread类的子类的实现步骤:
1·创建Thread类的子类
2·在子类中重写Thread类中的run方法(为了开辟出一个新的线程)
3·在主函数中创建子类的对象
4·子类的对象调用**start()**方法,目的为开启开辟出来的新线程(注意:一个对象只能开启一个线程,想要开启多个线程需要创建多个对象)
// 1·创建Thread类的子类
class Student extends Thread{
private String id ;
private String name;
private boolean gener;
public Student(String id, String name, boolean gener) {
this.id = id;
this.name = name;
this.gener = gener;
}
@Override
//开辟新的线程
public void run() {
for (int i = 0;i<5;i++) {
System.out.println(name+i);
}
}
}
public class TheradDemo1 {
public static void main(String[] args) {
//创建子类的对象
Student stu = new Student("001","Jamie",false);
//子类对象调用Thread中的start方法,开启线程
stu.start();
// 主线程
for(int i = 0;i<5 ;i++){
System.out.println("girl"+i);
}
}
}
上述代码的结果每次执行的结果都不相同,原因是因为线程使用抢占式优先的算法进行执行,哪个线程高就先执行哪一个线程,如果两个线程的优先级相同,就是谁抢到cpu资源,谁先执行。
上述代码在内存中的过程:
1·main方法,Jvm就会向cpu开辟一条路径。main方法在内存中开辟一个栈空间
2·创建Thread的子类对象stu,JVM就会向CPU再开辟一条路径。
3·stu.start(),执行Thread子类的run方法中的代码,这个时候内存中就会新开辟出一个属于stu对象的栈空间,用来存放stu对象的run方法。
4·这个时候内存中有两个占空间,有两条路径,CPU就会随机执行两个栈中的代码。
Thread的常用方法:
- public String getName():获取当前的线程名称
- public static Thread currentThread():获取当前线程的名称
- public void start():开启线程
- public void run():开辟新的线程
- public static void sleep(long millis):控制代码运行的时间,可以按自己定义的millis毫秒来暂停时间
Thread的构造方法:
- public Thread():分配一个新的线程对象
- public Thread(String name):可以修改线程的名称
- public Thread(Runnable target):分配一个带有指定目标的线程对象
- public Thread(Runnable target,String name):分配一个带有指定目标的带有名字的线程对象
注:父类的构造方法对子类的影响(从别人博客中取得):
子类不继承父类的构造方法,但父类的构造方法对子类构造方法的创建有影响。
具体来说就是:
①.当父类没有无参构造方法时:
1).子类也不能有无参构造方法;
2).且必须在子类构造方法中显式以super(参数)的形式调用父类构造方法;
否则会出现如下的错误:
Implicit super constructor Person() is undefined for default constructor. Must define an explicit constructor
3).子类在有参构造方法中显式调用super(参数)后,如果再写一个无参构造方法,则会出现下面的错误:
Implicit super constructor Person() is undefined. Must explicitly invoke another constructor
②.父类有无参构造方法时:
1).子类可以有无参构造方法;
2).也可以有有参构造方法;在有参构造方法中,可以用super显式调用父类构造方法也可以不调用;
也就是说,这时候,子类在构造方法的创建上是比较自由的。
测试Thread的常用方法
package TestThread;
/**
* Thread的常用方法:
* 1· 获取线程的当前线程的名字
* getName();可以使用对象.getName 也可以在run中直接getName
* Thread.currentThread().getName() :currentThread()静态方法,使用类名.方法名来获取
* 2· 修改线程的名字
* setName();通过子类对象来setName();
* 通过构造器传递新的名字给Thread父类,然后获取父类的获取名字的方法
* 3· sleep(long millis)延迟,可以用来控制线程的执行时间
*/
//测试获取线程的名字
class Person extends Thread{
@Override
public void run() {
//获取线程的名字方法一
String name1 = getName();
System.out.println("method1:"+name1);
//获取线程名字的方法二
System.out.println("method2:"+Thread.currentThread().getName());
}
}
//测试修改线程的名称
class Person2 extends Thread{
//修改线程名字
//第二种修改名字的方法,使用构造器
public Person2() {
}
public Person2(String name){
super(name);
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
//测试sleep 用sleep()来模拟秒表
class Clock extends Thread{
@Override
public void run() {
for (int i = 1;i<60;i++){
System.out.println(i);
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadMethods {
public static void main(String[] args) {
Person p1 = new Person();
// String name = p1.getName();
// System.out.println(name);
p1.start();
//获取主线程的方法名
System.out.println("主方法名:"+Thread.currentThread().getName());
//测试修改名称
Person2 p2 = new Person2();
p2.setName("Jamie");
p2.start();
Person2 p2_1 = new Person2("AAA");
p2_1.start();
//测试sleep()方法
Clock clock = new Clock();
clock.start();
}
}
2019年8月10 日的学习笔记就到这里 再会~