💡线程是程序执行流的最小单元💕💕. 它包含在进程之中,是进程中的实际运行单位,在Unix System V及SunOS中也被称为轻量进程(lightweight processes). 一个进程中可以并发多个线程,每个线程并行执行不同的任务🕛🕛🕛. 虽然多进程也能实现并发编程, 但是线程比进程更轻量(创建线程比创建进程更快,销毁线程比销毁进程更快,调用线程比调用进程更快 ).🫠🫠🫠
进程和线程的区别:
🙈🙈🙈 比如用于大型网游服务器的搭建,游戏画面实际需要 CPU 大量的在背后运算,使用多线程,可以更好的利用CPU多核计算资源,从而提高效率!!
👁️🗨️👁️🗨️👁️🗨️比如发博客,记录日志,读写硬盘等场景,这些业务需要花大量的时间进行等待,而 CPU 此时任务量小,合理利用CPU资源,也能提高效率!!
💡1.继承 Thread 类,重写run()方法.
class MyThread extends Thread {
@Override
public void run() {
while (true) {
System.out.println("继承 Thread 类");
}
}
}
public class Test {
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start();
}
}
重写 run() 方法创建出了一个线程对象,但此时线程对象并没有运行起来,相当于运动员已准备就绪. 此时需要调用 start() 方法,打出发令枪,线程才真正执行起来. 虽然调用 run() 方法也能得到相同结果,但系统内核并没有创建线程对象.
💡2.实现 Runnable 接口,重写run()方法.
class MyThread1 implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("实现 Runnable 接口");
}
}
}
public class Test1 {
public static void main(String[] args) {
Thread thread = new Thread(new MyThread1());
thread.start();
}
}
使用 jconsole 命令观察线程执行状态,
路径地址C:\ProgramFiles\Java\jdk1.8.0_191\bin\jconsole.exe.
💡3. 匿名内部类创建 Thread 子类对象.
public class Test2 {
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("匿名内部类创建 Thread 子类对象");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
}
休眠当前线程,可以调用 sleep() 方法,因为线程是随机调度的,实际休眠时间是大于等于设置的休眠时间的,也就是说,线程可能休眠完毕不会立即执行的.
💡4. 匿名内部类创建 Runnable 子类对象.
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println(" 匿名内部类创建 Runnable 子类对象");
}
System.out.println("线程结束");
}
});
thread.start();
Thread.sleep(3000);
thread.interrupt();
}
😋😋中断线程有两种方式,可以自己设定标记位来判断是否暂停当前线程,也可以调用 interrupt() 方法来通知.
1.如果thread线程没有处在阻塞状态,interrupt就会修改标记位.
2.如果thread线程处于阻塞状态, interrupt就会抛出异常信息,我们可以处理完毕任务之后,再跳出循环.
📢📢📢注意: 使用 interrupted() 方法判断当前线程的标志位是否设置,调用后清除标志位. 使用 isInterrupted() 方法调用后不清除标志位.
💡5. Lambda 表达式,理解困难,但是代码量是最少的.
public class Test4 {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("lambda 表达式");
});
System.out.println(thread.getState());
thread.start();
}
}
查看线程当前的状态,可以调用 getState() 方法,线程的状态一般分为:NEW 、 RUNNABLE 、 TERMINATED 、WAITING 、READY(就绪)、 BLOCKED 、 TIMED_WAITING几种状态.
🔽🔽🔽
NEW: 创建好Thread对象,但系统里并没有线程.
RUNNABLE: 线程可能正在运行中,也可能没在CPU上运行.
WAITING: 阻塞状态,线程中调用了 wait() 方法.
BLOCKED: 阻塞状态,线程中调用了 Synchronized() 方法.
TIMED_WAITING: 阻塞状态,线程中调用了 sleep() 方法.
TERMINATED: 线程已经执行完毕,系统里的线程已经销毁,但线程对象仍然存在.
💡数值a和b分别自增20_0000_0000次,观察它们的执行时间.
串行:
//串行
public static void serial() {
long str = System.currentTimeMillis();
int a = 0;
for (int i = 0; i < count; i++) {
a++;
}
int b = 0;
for (int i = 0; i < count; i++) {
b++;
}
long end = System.currentTimeMillis();
System.out.println("时间为:"+(end-str));
}
并发:
public static void concurrency() {
//并发
long str = System.currentTimeMillis();
Thread t1 = new Thread() {
@Override
public void run() {
int a = 0;
for (int i = 0; i < count; i++) {
a++;
}
}
};
Thread t2 = new Thread() {
@Override
public void run() {
int b = 0;
for (int i = 0; i < count; i++) {
b++;
}
}
};
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("时间为:"+(end-str));
}
等待一个线程,可以调用 join() 方法,考虑到线程是随机调度的,如果t1, t2 不执行完毕的话,直接调用currentTimeMillis() 方法,获取的时间是不合理的.
结果: