多线程初探

线程创建的三种方式

1,自定义类继承Thread类,即声明为Thread的子类,实现run方法
2,自定义类实现Runnable接口,创建自定义类对象,将此对象作为参数传递给Thread构造函数创建线程对象,好处,避免了java单继承的局限性,方便同一个对象被多个线程使用,Thread类就实现了Runnable接口
3,自定义类实现callable接口,实现接口中的call方法,相比于run方法,可以有返回值,可以抛出异常

线程的状态

​ 新建,Thread t1= new Thread(),创建线程对象时,就是新建状态
​ 就绪 t1.start() 线程调用start方法时,线程处于就绪状态,等待处理器调度
​ 运行 处理器调用线程执行时,线程处于运行状态,进入运行状态,线程才真正执行线程体代码块中的内容,run方法
​ 阻塞 当调用sleep,wait或同步锁定时,线程进入阻塞状态,阻塞事件解除后,重新进入就绪状态
​ 死亡 线程中断或结束,一旦进入死亡状态,不能再次启动线程

线程中的方法

​ 1,getName,setName,设置线程名,也可以通过构造方法设置线程名
​ 2,getId,获取线程Id,JVM会为每个线程分配一个Id,线程执行完后收回
​ 3,getPriority(),setPriority,线程优先级,一般线程优先级是5,最小1,最大10,优先级高的线程被处理器调度的几率大
​ 4,sleep,线程休眠,模拟网络延迟和倒计时等,Thread.sleep(毫秒数)
​ 5,join,某个线程调用join方法时表示,其他线程需要等待该线程执行完毕后才能开始执行
​ 6,setDaemon(boolean值),设置守护线程,当线程设置为守护线程时,其他线程执行完后,本线程将马上关闭/死亡/退出,JVM中的gc线程就是守护线程
​ 7,yield,线程让步,暂停当前正在执行的线程,使其回到就绪状态,把执行机会让给优先级相同或更高的线程,可能会礼让失败 因为线程回到就绪状态后,处理器可能还会调用它
​ 8,wait,线程等待,当线程调用wait方法时,线程会进入阻塞状态,直到另一个线程调用该对象的notify唤醒方法或者notifyAll方法
​ 9,notify,线程唤醒,唤醒正在等待的线程
​ 10,notifyAll,唤醒全体等待的线程
​ 11,isAlive,检测线程是否是活动状态,线程启动到线程死亡之前都是活动状态,方法返回值是Boolean值
​ 12,interrupt,中断方法,当线程调用该方法并不表示该线程中断,只是给线程设置了一个标志,通过调用isInterrupted方法判断线程是否被中断,如果是,则可以通过代码逻辑手动停止线程

注意:8,9,10方法实现了线程间的通信,方法必须在同步方法,同步代码块中使用,即synchronized关键字中使用

线程安全问题

非线程安全主要是指,多个线程对同一个对象的实例变量进行操作时,会出现值被更改,值不同步的情况。
线程安全问题表现为三个方面,原子性,可见性和有序性

  • 原子性
    Java有两种方式实现原子性,一种是使用锁,另一种利用处理器的CAS(Compare and Swap)指令。
    锁具有排他性,保证共享变量在同一时刻只能被一个线程访问,CAS指令直接在硬件(处理器和内存)层次上实现,看作硬件锁

  • 可见性
    在多线程环境中,一个线程对某个共享变量更新后,后续其他线程可能无法立即读到这个更新后的结果,这就是线程安全问题的另一种形式:可见性。
    如果一个线程对共享变量更新后,后续访问该变量的其他线程可以读到更新后的数据,称这个线程对共享变量的更新对其他线程可见。
    多线程程序因为可见性问题可能会导致其他线程读到旧数据(脏数据),说明线程对共享变量的修改不可见

  • 有序性
    有序性是指程序编译顺序和执行顺序并不一致,处理器在执行的时候,考虑到自身效率会对线程调度做出调整,这种现象被称为重排序,重排序可以分为两种,一种是指令重排序,一种是存储子系统重排序,指令重排序真实发生,存储子系统重排序是一种现象。

自身的问题

这里没继续看视频了,多线程中涵盖了非常多的知识点,准备在以后重新学习,没有太多时间,接下去的网络编程,servlet及EL表达式等等,我觉得很多很重要的东西,学校老师都没讲,匆匆就过去了,我也想打好基础,但时间不等我,总有一天我要掌握多线程,加油!!!