目录
1.前言
2.进程
提到线程,我们就不得不先了解进程了,那么什么是进程呢?进程就是运行起来的一个个程序。 引入进程有什么作用呢?是为了实现并发编程。但进程有很多,系统是如何管理它们的呢?那就是"先描述,再组织"。
3.线程
线程也叫做“轻量级进程”,创建线程,销毁线程,调度线程都比进程更快。但线程不能独立存在,要依附于进程,即一个进程至少包含一个线程!但每一个线程都是独立执行的,一个进程,最开始的时候必须要包含一个线程,这个线程负责完成执行代码的工作,也可以创建出多个线程,完成并发执行的效果。
4.线程和进程的区别
5.Thread创建线程
线程是操作系统的概念,操作系统提供了一些API可以操作线程,Java对系统API进行了封装,使用Thread类就可以创建出一个线程.
5.1继承Thread创建线程
方法1:
package Thread;
class MyThread extends Thread{
@Override
//线程的入口
public void run() {
while (true) {
System.out.println("hello thread");
//隔1s轮转
try {
Thread.sleep(1000);//1s
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
Thread t=new MyThread();
//start和run都是Thread的成员
//run只是描述线程的入口,线程主要做什么
//start则是真正的调用了系统API创建了线程,让线程再调用run()
t.start();
while (true){
System.out.println("hello main");
Thread.sleep(1000);
}
}
}
方法2:匿名内部类
package thread;
public class Demo3 {
public static void main(String[] args) {
Thread t = new Thread() {
//匿名内部类
@Override
public void run() {
while (true) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t.start();
while (true) {
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
注意
1.Thread在java.lang这个包下并不用导包
2.start方法内部会调用系统的API生成一个线程再调用run函数,和run函数的效果类似,但本质区别为:是否会创建一个线程
5.2实现Runnable接口
方法1:
package thread;
class MyRunnable implements Runnable {
@Override
public void run() {
while (true) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Demo2 {
public static void main(String[] args) {
Runnable runnable = new MyRunnable();
Thread t = new Thread(runnable);
t.start();
while (true) {
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
方法2:匿名内部类
package thread;
public class Demo4 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();
while (true) {
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
5.3lambda表达式
package thread;
public class Demo6 {
public static void main(String[] args) {
//lambda表达式
Thread t = new Thread(() -> {
while (true) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"第一个线程");
t.start();
while (true) {
System.out.println("hello main");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
6.Thread常见方法
6.1Thread常见属性
属性 | 获取方法 |
---|---|
ID | getId |
名称 | getName |
状态 | getState |
优先级 | getPriority |
是否后台线程 | isDaemon |
是否存活 | isAlive |
是否被中断 | isInterrupted |
6.2 中段一个线程- interrupt()
首先我们要知道,一个线程如果时间特别长,那么大概率在线程的内部有循环再一直执行。如果想要中断此线程,那么我们就想办法尽快让run函数执行完成,那么怎么能让循环快速执行完呢?其实我们只需要在循环处添加一个条件,条件不成立就结束了。
例如:
public class Demo7 {
public static boolean flag=false;
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(()->{
while (!flag){
System.out.println("t进程");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("工作完毕");
});
t.start();
Thread.sleep(5000);
flag=true;
System.out.println("打断进程");
}
}
注意
定义flag的时候只能定义为成员变量,不能定义为局部变量,因为在lambda有一个语法规则:变量捕获。把当前作用域的变量在lambda中复制了一份,在变量捕获时有一个前提限制:必须只能捕获final修饰的变量或者变量不能做任何修改。如果把flag设置为成员变量,就不再是变量捕获的与法律,而是内部类访问外部类的属性。
但是如果我们每次都专门定义一个标志位来打断线程是非常麻烦的,而且当处于睡眠模式下还不能立即就想应,在Thread类中有有一个标志位isInterupted来判定线程是否被打断。
public class Demo8 {
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(()->{
while (!Thread.currentThread().isInterrupted()){
System.out.println("t进程");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
//唤醒sleep有3种操作
//1.不管它,继续执行t线程
//2.立即执行打断
break;
//3.进行一些其他操作
}
}
});
t.start();
System.out.println("main进程");
Thread.sleep(5000);
System.out.println("t进程打断");
t.interrupt();//打断
}
}
说明
1.Thread.currentThread()表示当前线程即t线程
2.在正常情况下,sleep休眠时间完成才会被唤醒,如果调用interrupt()那么就提提前唤醒它触发InterruptedException异常
观察下图:虽然打断了t线程并且触发了InterruptedException异常,但t线程依然在执行。
出现上述情况是因为:interr唤醒sleep之后会抛出异常当同时也会清除标志位,这就使打断效果像没有生效一样。Java期望当线程收到“要中断”的信号使,由本身来决定接下来该怎么做。
6.3等待线程-jion()
等待一个线程即使指,当一个线程执行完毕时才能执行另外一个线程。
public class Demo9 {
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(()->{
for (int i=0;i<5;i++){
System.out.println("t线程正在执行");
}
});
t.start();
//等待t线程执行结束再执行main线程
t.join();
System.out.println("t线程执行结束");
System.out.println("main线程");
}
}
7.线程的状态
在进程中最核心的状态就是就绪和阻塞状态,在线程中同样适用,同时java又赋予了线程一些其他的状态:
2.1代码实现
public class Demo10 {
public static void main(String[] args) throws InterruptedException {
Thread t=new Thread(()->{
for (int i=0;i<3;i++){
System.out.println("t线程在执行");
}
});
System.out.println(t.getState());
t.start();
System.out.println(t.getState());
Thread.sleep(3000);
System.out.println(t.getState());
}
}
2.2运行结果
下期预告:线程安全问题