在JDK文件夹下面的bin中找到jconsole,然后选择本地连接,选择刚刚的java程序并双击打开。
如果打开了之后发现本地进程下什么都没有,可以试一下管理员运行。
左下角的这些 全都是当前进程的线程,来自于JVM自己创建的(负责垃圾回收,辅助完成调试,监控进程是否收到特殊信号之类),
下图的状态是JAVA自己搞的一个状态:
堆栈跟踪描述了当前线程,调用栈是啥样的,也就是方法之间相互调用的关联关系。
package threading;
/**
* Created with IntelliJ IDEA.
* Description:
* User: admin
* Date: 2022-11-29
* Time: 14:55
*/
//演示多线程的基本创建方式之一
class MyThread extends Thread {
//标准库提供了这个thread类,使用时需要继承这个类,相当于是对操作系统中的线程进行的封装。
@Override
public void run() {
//重写run方法,run是thread父类已经有的方法,这里需要重写一下,run里面的逻辑就是线程执行的工作。
//创建子类,重写run方法,相当于"安排任务"
while (true){
System.out.println("hello thread!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//sleep表示休眠,是让线程阻塞一段时间。后面参数单位是毫秒。
//使用sleep需要处理受查异常
}
}
}
public class demo1 {
public static void main(String[] args) {
MyThread t = new MyThread();
//创建一个mythread实例,并不会在系统中真的创建一个线程,只有当下面调用start方法的时候才会创建出线程。
//一直到run里面的代码执行完,新的线程就结束了。
t.start();//start会创建线程,在新线程中执行代码
//t.run();并没有创建线程,只是在原来线程中运行代码。只能在run方法里面循环
while (true){
System.out.println("hello main!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
//我们会看见两个内容交替打印,因为有两个执行流。
//两个线程在sleep阻塞后都会参与调度,导致抢占式执行,使用不能确定线程执行的顺序。
//运行了一次java程序就是启动了一个进程,一个进程李至少会有一个线程,默认的线程就是main方法所在的线程,也叫作主线程。
//main主线程和mythread创建的线程是并发加并行执行,也就是并发执行。
//两个线程,一个main方法对应的主线程(是JVM创建的,main就相当于线程的入口方法)。
//另一个my thread,run就是这个新线程的入口方法。
//JDK提供了jconsole工具进行查看。
package threading;
/**
* Created with IntelliJ IDEA.
* Description:
* User: admin
* Date: 2022-11-29
* Time: 18:01
*/
/*通过重写runnable方法来实现创建线程。
相对于第一种的方法,避免了把线程和项目耦合在一起的情况,减少了后续如果不用多线程用其他方式所产生的代码更换量。
只需要把Runnable传给其他地方就可以。
*/
class MyRunable implements Runnable{
@Override
public void run() {
while (true){
System.out.println("hello,world!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
}
public class demo2 {
public static void main(String[] args) {
MyRunable runable = new MyRunable();
//把线程要干的活和线程本身分开了,使用Runnable来专门表示线程要完成的工作
Thread t = new Thread(runable);
t.start();
Thread t2 = new Thread(runable);
t2.start();
while(true){
System.out.println("hello!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
package threading;
/**
* Created with IntelliJ IDEA.
* Description:
* User: admin
* Date: 2022-11-29
* Time: 18:15
*/
//使用匿名内部类来创建thread子类/runnable的方式。
public class demo3 {
public static void main(String[] args) {
//创建thread的子类同时实例化对象
Thread t = new Thread(){
@Override
public void run() {
while (true){
System.out.println("你好");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
};
t.start();
}
}
package threading;
/**
* Created with IntelliJ IDEA.
* Description:
* User: admin
* Date: 2022-11-29
* Time: 18:21
*/
public class demo4 {
public static void main(String[] args) {
Thread t = new Thread(new Runnable(){
@Override
public void run() {
while(true){
System.out.println("你好");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});
}
}
package threading;
/**
* Created with IntelliJ IDEA.
* Description:
* User: admin
* Date: 2022-11-29
* Time: 18:24
*/
//使用lamdba表达式,本质上他是一个匿名函数,
public class demo5 {
public static void main(String[] args) {
Thread t = new Thread( () -> {
while(true){
System.out.println();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
}
}
package threading;
/**
* Created with IntelliJ IDEA.
* Description:
* User: admin
* Date: 2022-11-29
* Time: 18:35
*/
public class demo6 {
public static final long COUNT = 100_0000_000 ;
public static void main(String[] args) {
serial();
concurrency();
}
//串行执行任务
public static void serial () {
long beg = System.currentTimeMillis();
long a = 0;
for (int i = 0; i < COUNT; i++) {
a++;
}
a=0;
for (long i = 0; i < COUNT; i++) {
a++;
}
long end = System.currentTimeMillis();
System.out.println("执行时间间隔:" + (end-beg)+ "ms");
}
//并发执行任务
public static void concurrency() {
long beg = System.currentTimeMillis();
Thread t1 = new Thread(() -> {
long a = 0;
for (long i = 0; i < COUNT; i++) {
a++;
}
});
Thread t2 = new Thread(() -> {
long a = 0;
for (long i = 0; i < COUNT; i++) {
a++;
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//串行没有创建额外线程,并发额外创建了两个线程。
//使用join来阻塞等待,线程的结束,在main中调用t1就是让main线程阻塞(停下来不继续执行)一直到t1执行完
long end = System.currentTimeMillis();
System.out.println("执行的时间为: " + (end-beg) + "ms");
}
}
Thread()
创建线程对象
Thread(Runnable target)
使用Runnable对象创建线程对象
Thread(String name)
创建线程对象并命名
Thread(Runnable target, String name)
使用Runnable创建线程对象并命名
Thread(ThreadGroup group,Runnable target)
线程可以用来分组管理,分好的组叫做线程组
举例子如下:
public class demo7 {
public static void main(String[] args) {
Thread t1 = new Thread();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
}
});
Thread t3 = new Thread("你好");
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
}
},"你好");
}
}
ID id是线程的唯一标识,不同线程不会重复
getid()
是java中给thread对象安排的身份标识,和操作系统中的pcb的pid和线程api中的id都不一样
名称 名称是各种调试工具用到
getName()
状态 表示线程当时所处的一个情况
getState()
优先级 优先级高的线程理论上来说更容易被调度到
getPriority()
是否后台线程 JVM在一个进程中的所有非后台线程结束后才会结束
isDaemon()
默认创建的是前台线程,会阻止进程退出,如果main运行完了前台现场还没完,进程就不会退出。
如果是后台进程,后台进程不阻止进程退出,如果main等前台前台进程执行完了,这个时候后台线程没执行完,进程也会退出。
是否存活 判断run方法是否结束
isAlive()
thread对象出来了,内核线程还不一定有,只有调用start方法内核线程才有,内核的线程执行完了,内核的线程就销毁了,但是thread对象还在
是否被中断
isInterruoted()
public class demo7 {
public static void main(String[] args) {
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println("1000");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
},"你好");
// 通过setDaemon来设置成后台线程,需要用于start之前设置。
t4.setDaemon(true);
t4.start();
System.out.println("main线程执行结束");
}
}
public class demo7 {
public static void main(String[] args) {
Thread t4 = new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println("1000");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
},"你好");
// 通过setDaemon来设置成后台线程,需要用于start之前设置。
t4.setDaemon(true);
t4.start();
System.out.println(t4.getId());
System.out.println(t4.getName());
System.out.println(t4.getPriority());
System.out.println(t4.getState());
System.out.println(t4.isDaemon());
System.out.println(t4.isAlive());
System.out.println(t4.isInterrupted());
System.out.println("main线程执行结束");
}
}
让run方法提前一点结束的方法(本质是让run方法尽快结束,并不是强制结束)
//定义一个标志位,使用sleep来控制while循环的时间
public class demo8 {
private static boolean isquit = false;
public static void main(String[] args) {
Thread t = new Thread(() ->{
while(!isquit){
System.out.println("hello");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("t线程执行完了");
});
t.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
isquit = true;
System.out.println("设置让t线程结束");
}
}
或者用interrupt和break
public class demo9 {
public static void main(String[] args) {
Thread t = new Thread(() ->{
//currentThread是thread的静态方法,通过这个方法可以拿到当前线程的实例,也就是拿到当前线程对应的thread对象
while(!Thread.currentThread().isInterrupted()){
System.out.println("hello");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//这里不需要打印异常了
//线程稍后处理可以在后面加
//Thread.sleep(1000);
break;
}
}
System.out.println("t线程执行完了");
});
t.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
t.interrupt();
//在主线程中通过t.interrupt来设置标志位为true,从而中断线程。
//interrupt有两种情况
//1 interrupt在线程运行状态会设置标志位为true
//2 t线程在阻塞状态也就是sleep不会设置标志位,而是触发InterruptException会把sleep提前唤醒
//
System.out.println("设置让t线程结束");
}
}
使用join来阻塞线程
join可以通过一些特殊操作,来对线程的执行顺序作出干预,其中join就是一个方法,控制线程之前的结束顺序,
java中的多线程方法,只要会造成线程阻塞,就有可能会抛出interruptException异常
public class demo10 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("hello");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
System.out.println("之前");
try {
t.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("之后");
}
}
java认为自带的状态不是很合适,于是自己搞了一套状态规则
主要状态是 就绪 阻塞 运行三个情况
NEW:Thread
对象创建了出来,但是内核的PCB还没有创建(还没有创建线程)
TERMINATED
内核的PCb销毁了,但是Thread对象还在
RUNNABLE
就绪状态(在CPU上运行,在就绪队列中排队)
TIMED_WAITING
按照一定时间,进行阻塞,例如sleep
WAITING
特殊的阻塞状态。调用wait
BLOCKED
等待锁的时候进入的阻塞状态