JAVAEE-多线程

在JDK文件夹下面的bin中找到jconsole,然后选择本地连接,选择刚刚的java程序并双击打开。

如果打开了之后发现本地进程下什么都没有,可以试一下管理员运行。

 左下角的这些 全都是当前进程的线程,来自于JVM自己创建的(负责垃圾回收,辅助完成调试,监控进程是否收到特殊信号之类),

 下图的状态是JAVA自己搞的一个状态:

 堆栈跟踪描述了当前线程,调用栈是啥样的,也就是方法之间相互调用的关联关系。

创建线程

继承thread来创建:

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工具进行查看。

实现runnable来创建:

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);
            }
        }
    }
}

继承thread或者实现runnable后使用匿名内部类创建:

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);
                    }
                }
            }
        });
    }
}

使用lamdba表达式创建:

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()
创建线程对象

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() {
                
            }
        },"你好");
    }
}

Thread的几个常见属性

ID  id是线程的唯一标识,不同线程不会重复
getid()
是java中给thread对象安排的身份标识,和操作系统中的pcb的pid和线程api中的id都不一样

名称  名称是各种调试工具用到
getName()

状态  表示线程当时所处的一个情况
getState()

优先级  优先级高的线程理论上来说更容易被调度到
getPriority()

是否后台线程  JVM在一个进程中的所有非后台线程结束后才会结束
isDaemon()
默认创建的是前台线程,会阻止进程退出,如果main运行完了前台现场还没完,进程就不会退出。
如果是后台进程,后台进程不阻止进程退出,如果main等前台前台进程执行完了,这个时候后台线程没执行完,进程也会退出。

是否存活  判断run方法是否结束
isAlive()
thread对象出来了,内核线程还不一定有,只有调用start方法内核线程才有,内核的线程执行完了,内核的线程就销毁了,但是thread对象还在

是否被中断
isInterruoted()

isDaemon和后面属性实例

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("之后");
    }
}

PCB状态(用.getState可以得到的状态)

java认为自带的状态不是很合适,于是自己搞了一套状态规则

主要状态是 就绪 阻塞 运行三个情况

NEW:Thread
对象创建了出来,但是内核的PCB还没有创建(还没有创建线程)

TERMINATED
内核的PCb销毁了,但是Thread对象还在

RUNNABLE
就绪状态(在CPU上运行,在就绪队列中排队)

TIMED_WAITING
按照一定时间,进行阻塞,例如sleep

WAITING
特殊的阻塞状态。调用wait

BLOCKED
等待锁的时候进入的阻塞状态

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值