多线程是指从软件或硬件上实现多个线程并发执行的技术
具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程,提升性能。
并发和并行
并发:在同一时刻,有多个指令在单个CPU上交替执行
并行:在同一时刻,有多个指令在多个CPU上同时执行
进程和线程
进程:正在运行的软件
- 独立性:进程是一个独立运行的基本单位,同时也是系统分配资源和调度的独立单位。
(个人理解:每个不同的软件互不相关,独立运行) - 动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡。
- 并发性:任何进程可以同其他进程一起并发执行
线程:进程中的单个顺序控制流,是一条执行路径
(个人理解:程序中的一个个功能,如:360的杀毒,清理垃圾,优化加速...)
单线程:一个进程如果只有一条执行路径,则称为单线程程序
(输出语句,循环等)
多线程:一个进程有多条执行路径,则称为多线程程序
(如以上例子的360)
多线程的实现方式:
- 继承Thread类的方式进行实现
- 实现Runnable接口的方式进行实现
- 利用Callable和Future接口方式实现
-----------------------------------------------------------❤-----------------------------------------------------------
1、继承Thread类的方式
MyThreadDemo01
public class MyThreadDemo01 extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("我光速炒了第("+i+")道菜");
}
}
}
Demo
//线程之间的执行具有随机性
MyThreadDemo01 m = new MyThreadDemo01();
MyThreadDemo01 m2 = new MyThreadDemo01();
// 此方法的运行结果是两个对象先后执行完毕,并未交替
// 表示的仅仅是创建对象,用对象调用方法,并未开启线程
// m.run();
// m2.run();
//交替运行
m.start();
m2.start();
为何要重写run方法?
因为run方法是用来封装被线程执行的代码
2、实现Runnable接口的方式
MyRunnable
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("我此刻继续再炒(" + i +")道菜");
}
}
}
Demo
public class Demo {
public static void main(String[] args) {
//创建参数对象
MyRunnable mr = new MyRunnable();
//创建线程对象
Thread t1 = new Thread(mr);
t1.start();
MyRunnable mr2 = new MyRunnable();
//创建第二个线程对象
Thread t2 = new Thread(mr2);
t2.start();
}
}
3、利用Callable和Future接口方式
MyCallable
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println("我真挚地向fxy表白了(" + i + ")次");
}
return "她终于答应我了,我感动的流下了泪水";
}
}
Demo
public class Demo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable mc = new MyCallable();
//此对象的作用:可以获取线程执行完毕后的结果,也可以作为参数传递给Thread对象(因为此对象实现了Runnable接口)
FutureTask<String > ft = new FutureTask<>(mc);
//创建线程对象
Thread t= new Thread(ft);
t.start();
//获取线程运行后的结果
String s = ft.get();
System.out.println(s);
}
}
运行结果:
获取和设置线程的名称:
getName():获取
setName():设置
MyThread
public class MyThread extends Thread{
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
//直接调用Thread中的方法获取线程的名字
System.out.println(getName() + "......❤......" + i);
}
}
}
Demo
public class Demo {
public static void main(String[] args) {
//要在MyTread类中设置构造方法public MyThread(String name)
MyThread t1 = new MyThread("小龙");
MyThread t2 = new MyThread("关羽");
// t1.setName("小龙");
// t2.setName("关羽");
t1.start();
t2.start();
}
}
获取线程对象:
publicstaticThread currentThread():返回对当前正在执行的线程对象的引用;
使用方式: String name = Thread.currentThread().getName(); System.out.println(name); 或在Runnable中使用获取线程对象的名称 Thread.currentThread().getName();
线程休眠:
publicstatic void sleep(long time):让线程休眠指定的时间,单位为毫秒
//没有创建线程,是主线程运行的
//System.out.println("睡前");
//Thread.sleep(2000);
//System.out.println("睡醒啦");
MyRunnable mr = new MyRunnable();
Thread t= new Thread(mr);
Thread t2= new Thread(mr);
t.start();
t2.start();
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "...speed:" +i);
}
}
后台线程/守护线程
publicfinalvoid setDaemon(boolean on):设置为守护线程。
public class MyThread1 extends Thread{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+ "..." +i);
}
}
}
public class MyThread2 extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName()+ "..." +i);
}
}
}
public class Demo {
public static void main(String[] args) {
MyThread1 m1 = new MyThread1();
MyThread2 m2 = new MyThread2();
m1.setName("女神");
m2.setName("战狼(滋溜~)");
//设置为守护线程
m2.setDaemon(true);
m1.start();
m2.start();
}
}
当女神线程终止后,战狼也随之停止。