文章目录
1、操作系统相关知识
2、java程序运行
java命令启动java程序的原理
- java命令,创建jvm进程
- jvm进程创建一个线程,主线程 main
- 执行主线程中的main方法
jvm是单线程还是多线程
- jvm是多线程的,起码有一个垃圾回收线程
3、多线程的实现方式一:继承Thread
文档实例
Thread类线程 是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。
步骤
- 继承Thread类
- 重写里面的run方法
- 创建子类对象
- start方法去启动线程
示例:
public class Demo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
// 启动线程
myThread.start();
}
}
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
}
}
获取设置线程名称
-
获取 getName()
- 默认线程名 Thread-0 类名+数字
-
设置 setName()
-
Thread(String name) 分配新的 Thread 对象。
如何获取主线程的名称
public class Demo1 {
public static void main(String[] args) {
// static Thread currentThread()
// 返回对当前正在执行的线程对象的引用。
Thread thread = Thread.currentThread();
System.out.println(thread.getName());
MyThread myThread = new MyThread("吴彦祖");
myThread.start();
}
}
class MyThread extends Thread {
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName() + "---" + i);
}
}
}
注意事项
- 一个Thread或Thread子类对象才代表一个线程
- 为什么要重写run方法?
- 只有Thread中的run方法中代码才会在子线程中执行
- 为了保证子线程中运行的是我们的想要他执行的代码,我们要重写run方法(换句话说,把我们想要在子线程中执行的任务封装在了run方法中)
- 一个方法,被哪个线程调用,这个方法就运行在调用它的那个线程当中
- 启动线程,必须要用start方法而不是run方法。如果只是线程对象.run() 那么这仅仅只是普通方法调用。
- 同一个Thread对象或子类对象只能被启动一次。如果我想启动多个线程的话,只能创建多个对象IllegalThreadStateException
4、线程调度方式
两种调度方式
线程调度是指系统为线程分配处理器使用权的过程。
调度的方式主要有两种:
-
协同式线程调度。
a. 如果使用协同式调度的多线程系统,线程的执行时间,由线程本身来控制,线程把自己的工作执行完了之后
主动通知系统切换到另外一个线程上去。b. 其最大的好处是实现简单,坏处是线程执行时间不可控
-
抢占式线程调度
a. 如果使用抢占式调度的多线程系统,那么每个线程将由系统来分配执行时间,线程的切换不由线程本身决定。
b. 其最大的好处是,线程的执行时间是可控的
java中采用的是抢占式线程调度方式
5、线程优先级
操作系统的线程调度
- 静态优先级+动态优先级
- 正在CPU上执行的线程会随着执行时间的延长而降低优先级,等待的线程会随着等待的时间的延长优先级而升高
获取 设置优先级
- get 和 set方法
public class Demo2 {
public static void main(String[] args) {
MyThread2 t1 = new MyThread2();
MyThread2 t2 = new MyThread2();
t1.setName("短风");
t2.setName("细风");
// 设置线程优先级 线程优先级的范围1-10
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
// 获取优先级
// 默认优先级 5
int priority = t1.getPriority();
System.out.println(priority);
int priority2 = t2.getPriority();
System.out.println(priority2);
}
}
class MyThread2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+"----"+i);
}
}
}
为什么大的优先级没有先执行?
我们设置的优先级是静态优先级,仅仅只是给操作系统的一种建议.
java官方: 线程优先级并非完全没有用,我们Thread的优先级,它具有统计意义,总的来说,高优先级的线程占用的cpu执行时间多一点,低优先级线程,占用cpu执行时间,短一点
6、线程控制API
6.1 休眠线程sleep
public class SleepThreadDemo {
public static void main(String[] args) {
SleepThread t = new SleepThread();
t.start();
}
}
class SleepThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+"---"+i);
try {
//Thread.sleep(2000);
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
6.2 合并线程join
2个问题
- 谁等待:调用join的代码在哪个线程中运行就是哪个线程等待
- 等待谁:等待调用join的那个线程
public class JoinThreadDemo {
public static void main(String[] args) {
System.out.println("main start");
JoinThread joinThread = new JoinThread();
joinThread.setName("55开");
joinThread.start();
try {
joinThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main end");
}
}
class JoinThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+"----"+i);
}
}
}
6.3 守护进程daemon
分类:
- 用户线程
- 守护线程
setDaemon(boolean on) 将该线程标记为守护线程或用户线程。
注意;
将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。
该方法必须在启动线程前调用。
java.lang.IllegalThreadStateException:启动线程之后调用
6.4 礼让线程yield
static void | yield() 暂停当前正在执行的线程对象,并执行其他线程。 |
---|---|
public class YieldThreadDemo {
public static void main(String[] args) {
YieldThread t1 = new YieldThread();
YieldThread t2 = new YieldThread();
t1.setName("金牌讲师");
t2.setName("粤港澳第一赌神");
t1.start();
t2.start();
}
}
class YieldThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+"----"+i);
// yield() 暂停当前正在执行的线程对象,并执行其他线程。
Thread.yield();
// 为什么没有你一个我一个的执行呢?
// 虽然调用了yield方法,放弃CPU的执行权,但是java采用的是抢占式调度方式
// 仍然会参加下一轮的CPU竞争 并不能保证一定保证被哪个线程抢到执行权.
}
}
}
6.5 中断线程stop,interrupt
练习:
安全的终止线程
提示: 用flag标记 如果为true 正常执行 如果为false 终止线程执行
在终止之前,去做一个日志保存 , 将终止信息保存到log.txt当中
利用FileWriter , 2021-4-28 时分秒 : 某个线程 终止了
public class SecurityStopDemo {
public static void main(String[] args) {
StopThread2 stopThread2 = new StopThread2();
stopThread2.setName("张三");
stopThread2.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
stopThread2.flag = false;
}
}
class StopThread2 extends Thread {
boolean flag = true;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (flag) {
System.out.println(getName() + "----" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
// flag 为 false说明线程终止
System.out.println("线程终止");
// 记录哪个线程 什么时间发生了中断
try {
FileWriter fileWriter =
new FileWriter("../day19_thread02/log.txt");
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatTime = simpleDateFormat.format(new Date());
String s = formatTime + ": " + getName() + " 发生了中断,数据已保存";
fileWriter.write(s);
fileWriter.write(System.lineSeparator());
fileWriter.flush();
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
// 进行一些数据保存的操作
return;
}
}
interrupt
如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。
public class InterruptThreadDemo {
public static void main(String[] args) {
StopThread3 stopThread3 = new StopThread3();
stopThread3.setName("女流");
stopThread3.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 抛出中断异常 相当于泼了一盆冷水
stopThread3.interrupt();
}
}
class StopThread3 extends Thread {
@Override
public void run() {
System.out.println("stop before");
for (int i = 0; i < 10; i++) {
System.out.println(getName()+"----"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//e.printStackTrace();
System.out.println("有异常");
}
}
System.out.println("stop end");
}
}
stop
public class ThreadStopDemo {
public static void main(String[] args) {
ThreadStop threadStop = new ThreadStop();
threadStop.setName("短风");
threadStop.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 会终止线程执行
threadStop.stop();
}
}
class ThreadStop extends Thread{
@Override
public void run() {
System.out.println("ThreadStop start");
for (int i = 0; i <10; i++) {
System.out.println(getName()+"-----"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("ThreadStop end");
}
}