java基础学习之多线程
并发和并行
并发:cpu交替执行任务
并行:cpu同时执行任务
进程和线程
进程(进行中的程序):程序的一次运行,也是一个在内存中运行的应用程序。
线程:线程属于进程,进程的一个执行单元,是一条程序通向cpu的路径。
如果是单核单线程的cpu,它的线程会快速的在多个线程中切换,不如多核多线程的cpu速度快。
线程调度
1、分时调度:所有线程轮流使用cpu,平均分配每个线程占用cpu的时间.
2、抢占式调度:优先让优先级高的线程使用cpu,如果优先级相同,那么会随机选择一个(随机选择性),java使用抢占式调度。
主线程:执行main方法的线程
创建多线程程序的第一种方法:创建Thread类的子类
1、创建Thread类的子类
2、重写run()方法
3、创建Thread类的子类对象
4、调用start方法,开启新线程,执行run()方法
start() 方法使线程开始执行,JVM会调用run()方法。
多个线程并发的执行,也就是cpu会快速的在多个线程之间切换。
java实行抢占式调度,优先让优先级高的线程先执行,相同优先级的线程随机执行。
一般情况下,主线程和后创建的子线程优先级相同。(可能)
注意:
1、是调用start()方法才会开启新线程。
2、一个线程对象不能重复start(),会报错。
Thread类(线程类)
获取线程名称的方法
String getName()获取线程的名称
currentThread()返回对当前正在执行的线程对象的引用
//创建一个Thread类的子类
public class MyThread extends Thread{
//重写Thread类的run()方法,设置线程任务(开启线程要干什么)
@Override
public void run() {
// String name = getName();//getName()方法获取线程的名称
// System.out.println(name);
System.out.println(currentThread().getName());//currentThread()方法获取当前正在运行的线程 返回对当前正在执行的线程对象的引用
}
/*
执行结果:
main
Thread-0
Thread-1
*/
}
public class Test {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
new MyThread().start();
String name = Thread.currentThread().getName();
System.out.println(name);
}
}
设置线程名称的方法
1、setName()方法
2、创建Thread类的子类时,调用父类Thread的带参构造方法,设置线程名称。
public class MyThread2 extends Thread{
public MyThread2(String name){
super(name);
}
@Override
public void run() {
System.out.println(getName());
}
}
public class Test2 {
public static void main(String[] args) {
MyThread2 mt = new MyThread2("小强");
// mt.setName("小强");
mt.start();
}
}
Sleep()方法
使线程以相应的毫秒值暂停
public class SleepTest {
public static void main(String[] args) {
/*
每隔一秒输出一个数字
*/
for (int i = 0; i < 5; i++) {
System.out.println(i);
try {
Thread.sleep(1000);//sleep方法使线程以相应的毫秒值暂停
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
创建多线程程序的第二种方式实现Runnable接口
Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。类必须定义一个称为 run 的无参数方法。
1、创建Runnable接口的实现类、实现run()方法,设置线程任务
2、创建Runnable接口的实现类对象
3、创建Thread类对象,构造方法传递Runnable接口的实现类对象
4、Thread类对象调用start()方法,开启新线程,调用run()方法
public class RunnableImpl implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
public class Test {
public static void main(String[] args) {
RunnableImpl rp = new RunnableImpl();
Thread thread = new Thread(rp);
thread.start();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+i);
}
}
}
使用Thread和Runnable实现多线程的区别
1、避免了单继承的局限性
一个类只能继承一个类(一个人只能有一个爹),类继承了Thread类就不能继承其它类。
实现了Runnable接口还可以继承其它类实现其它接口。
2、增强了程序的扩展性,降低了程序的耦合性(解耦)
实现Runnable接口的方式,把设置线程任务和开启新线程进行了分离
实现类中重写了run()方法,用来设置线程任务
创建Thread类对象,调用start()方法,用来开启新线程
匿名内部类方式实现线程的创建
匿名:没有名字
内部类:写在其它类内部的类
匿名内部类的作用:
把子类继承父类,重写父类的方法,创建子类对象合成一步完成。
把实现类实现接口,重写接口中的方法,创建实现类对象合成一步完成。
匿名内部类的最终产物:子类/实现类对象,而这个类没有名字
格式:
newThread(){
重写run()方法
},start();
new Thread(new Runnable(){
重写run()方法
}).start();