美文网首页
多线程基础

多线程基础

作者: 俗人浮生 | 来源:发表于2019-01-15 21:59 被阅读0次

要说多线程,首先我们得先了解一下线程的几种状态,查看Thread类的源码,里面有一个枚举型:

public enum State {
        NEW,  //新建
        RUNNABLE,  //运行
        BLOCKED,   //锁池
        WAITING,    //等待
        TIMED_WAITING,  //定时等待
        TERMINATED;  //终止、结束
    }

故此,线程的状态只有以上6种,而像阻塞状态,可运行状态,挂起状态这些是人们为了便于理解加上去的。
为了更好地理解线程的6种状态,我写了以下demo:

 public static void main(String[] args) {
        Thread mainThread=Thread.currentThread();
        Thread thread =new Thread("tt"){
            @Override
            public void run() {
                super.run();
                try {
                    Thread.sleep(2000);
                    System.out.println("main线程状态1:"+mainThread.getState());
                    System.out.println("tt线程状态4:"+getState());
                    synchronized (this){
                        notify();
                        System.out.println("main线程状态2:"+mainThread.getState());
                    }
                    Thread.sleep(1000);
                    System.out.println("main线程状态4:"+mainThread.getState());
                    System.out.println("tt线程状态6:"+getState());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        System.out.println("tt线程状态1:"+thread.getState());
        thread.start();
        System.out.println("tt线程状态2:"+thread.getState());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("tt线程状态3:"+thread.getState());
        synchronized (thread){
            try {
                thread.wait();
                System.out.println("main线程状态3:"+mainThread.getState());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("tt线程状态5:"+thread.getState());
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main线程状态5:"+mainThread.getState());
        System.out.println("tt线程状态7:"+thread.getState());
    }

这段小demo包含了线程使用的几个重要方法,也涵盖了线程的6个状态,运行结果如下:

tt线程状态1:NEW
tt线程状态2:RUNNABLE
tt线程状态3:TIMED_WAITING
main线程状态1:WAITING
tt线程状态4:RUNNABLE
main线程状态2:BLOCKED
main线程状态3:RUNNABLE
tt线程状态5:TIMED_WAITING
main线程状态4:WAITING
tt线程状态6:RUNNABLE
main线程状态5:RUNNABLE
tt线程状态7:TERMINATED

借用网上一张图(侵删)来更好滴描述一下线程的6个状态: 线程状态转换图

为了便于复习巩固,以下记录一下线程的相关知识点:

1.Thread启动方法start()与run()的区别

start()会启动一个新线程,并执行run方法,不能被重复调用
run()就和普通的成员方法一样,调用不会启动新线程,可重复调用

2.synchronized关键字

在java中,每个对象都有且仅有一个同步锁,也就是说同步锁是依赖于对象存在的。
多线程对同步锁访问是互斥的!
实例锁:作用于实例对象; 全局锁:针对的是类,比如静态,其中,单例对象也相对于全局锁。

3.wait()和notify()

wait()的作用是让当前线程处于等待状态,并释放同步锁
notify()的作用是唤醒当前对象上的等待线程
需注意的是:比如上面demo例子中调用: thread.wait();
因为当前线程是main线程,所以调用后是使main线程处于等待状态,而不是thread处于等待状态。
另外,调用wait()和notify()的地方都需要拥有同步锁,因为wait()是要释放同步锁的,而notify()是根据同步锁来进行线程唤醒的,故此等待和唤醒的过程依赖于同一个同步锁。
而正如前面所说的,同步锁依赖于对象,这也就是为什么wait()和notify()方法是定义在Object类中,而不是Thread中的原因(面试题)

4.yield()和wait()

yield()就是让步,能够让线程从“运行状态”转为“可运行状态”或“就绪状态”(不属于6个状态之一),从而让其它具有相同优先级的等待线程获取执行权,但这一点并不保证,有可能下一刻它又再次处于“运行状态”。
wait()是让线程从“运行状态”转为“等待状态”,同时释放同步锁。yield()并不会释放锁。

5.join()

join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行,其状态从“运行状态”转为“等待状态”。

6.线程的终止

Thread类中,终止线程的方法有:stop()、suspend()和interrupt(),其中前两个因安全问题已被废弃,所以一般我们用interrupt()来进行线程的终止。
调用interrupt()时,我们需区分线程的状态进行讨论:
A当线程处于“等待状态”或“定时等待状态”时,若调用interrupt(),会将中断标记为设置为true,但由于线程目前处于阻塞中,故中断标记位又立即被清空为false,并抛出InterruptedException的异常
B当线程处于“运行状态”时,若调用interrupt(),中断标记位为被设置为true
C当线程处于“终止状态”时,若调用interrupt(),不会产生任何操作
获取当前线程中断标记位的方法有:isInterrupted()和interrupted(),两者的区别在于:
interrupted()返回当前中断标记位,并进行清空,即返回后将中断标记位设置为false
isInterrupted()仅仅返回中断标记位

7.线程的分类及优先级

线程可分为用户线程和守护线程,通过isDaemon()方法来进行区分,true为“守护线程”,false为“用户线程”。
线程的优先级范围为1-10,默认为5,“高优先级线程”会优先于“低优先级线程”执行。
我们可通过setDaemon(true)来设置一个线程为守护线程,通过setPriority(X)来设置线程的优先级。
当满足以下两个条件之一时,JVM就会终止运行:
A调用了exit()方法,并且exit()有权限被正常执行。
B所有的“非守护线程”都死了(即JVM中仅仅只有“守护线程”)。

相关文章

网友评论

      本文标题:多线程基础

      本文链接:https://www.haomeiwen.com/subject/mbrudqtx.html