线程的生命周期、方法、关键字

 

 可以看出只有就绪状态和运行状态能够相互转换

1、线程的生命周期?线程有几种状态

1.线程通常有五种状态,创建,就绪,运行、阻塞和死亡状态。
        1.1新建状态(New):新创建了一个线程对象。
        1.2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
        1.3.运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
        1.4.阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
        1.5.死亡状态(Dead):线程执行完了或者因异常退出了run方法,该线程结束生命周期。
2.阻塞的情况又分为三种:
        (1)、等待阻塞:运行的线程执行wait方法,该线程会释放占用的所有资源,JVM会把该线程放入等待池”中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notifynotifyAll方法才能被唤醒,waitobject类的方法
        (2)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入“锁池中。
        (3)、其他阻塞:运行的线程执行sleepjoin方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep状态超时、join等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
        sleep是Thread类的方法

2、sleep()wait()join()yield()的区别

  2.1 首先了解一下等待池和锁池

        1.等待池

        当我们调用wait()方法后,线程会放到等待池当中,等待池的线程是不会去竞争同步锁。只有调用了notify()或notifyAll()后等待池的线程才会开始去竞争锁,notify()是随机从等待池选出一个线程放到锁池,而notifyAll()是将等待池的所有线程放到锁池当中。

        2.锁池

        所有需要竞争同步锁的线程都会放在锁池当中,比如当前对象的锁已经被其中一个线程得到,则其他线程需要在这个锁池进行等待,当前面的线程释放同步锁后锁池中的线程去竞争同步锁,当某个线程得到后会进入就绪队列进行等待cpu资源分配。

  2.2 sleep和wait的区别:

        1、sleep Thread 类的静态本地方法,wait 则是 Object 类的本地方法。
        2、sleep方法不会释放lock,但是wait会释放,而且会加入到等待队列中。
      sleep就是把cpu的执行资格和执行权释放出去,不再运行此线程,当定时时间结束再取回cpu资源,参与cpu的调度,获取到cpu资源后就可以继续运行了。而如果sleep时该线程有锁,那么sleep不会释放这个锁,而是把锁带着进入了冻结状态,也就是说其他需要这个锁的线程根本不可能获取到这个锁。也就是说无法执行程序。如果在睡眠期间其他线程调用了这个线程的interrupt方法,那么这个线程也会抛出interruptexception异常返回,这点和wait是一样的。
        3、sleep方法不依赖于同步器synchronized,但是wait需要依赖synchronized关键字。
        4、sleep不需要被唤醒(休眠之后推出阻塞),但是wait需要(不指定时间需要被别人中断)。
        5、sleep 一般用于当前线程休眠,或者轮循暂停操作,wait 则多用于多线程之间的通信。
        6、sleep 会让出 CPU 执行时间且强制上下文切换,而 wait 则不一定,wait 后可能还是有机会重新竞争到锁继续执行的。

  2.3 yieldjoin的区别:

  • yield()执行后线程直接进入就绪状态,马上释放了cpu的执行权,但是依然保留了cpu的执行资格, 所以有可能cpu下次进行线程调度还会让这个线程获取到执行权继续执行
  • join()执行后线程进入阻塞状态,例如启动A线程后,立即调用B线程的join()方法,则线程B会进入到阻塞队列,直到线程A结束或中断线程之后线程B才会继续执行

3.volatile、synchronized、Lock的区别

        2.1 synchronized与Lock的区别

  1. synchronized是Java关键字,在JVM层面实现加锁和解锁;Lock是一个接口,在代码层面实现加锁和解锁。

  2. synchronized可以用在代码块上、方法上;Lock只能写在代码里。

  3. synchronized在代码执行完或出现异常时自动释放锁;Lock不会自动释放锁,需要在finally中显示释放锁。

  4. synchronized会导致线程拿不到锁一直等待;Lock可以设置获取锁失败的超时时间。

  5. synchronized无法得知是否获取锁成功;Lock则可以通过tryLock得知加锁是否成功。

  6. synchronized锁可重入、不可中断、非公平;Lock锁可重入、可中断、可公平/不公平,并可以细分读写锁以提高效率。

        2.2 volatile和synchronized的区别:

  1. volatile 关键字只能修饰变量,而synchronized可以修饰方法和普通代码块,但不能修饰静态代码块。
  2. volatile关键字不会发生阻塞,而synchronized关键字可能会阻塞
  3. volatile关键字主要解决数据的可见性和有序性,但是不完全保证数据的原子性,synchronized保证了数据的可见性、有序性和原子性。

4.并发、并行和串行

        区别:

  • 串行在时间上不可能发生重叠,前一个任务没搞定,下一个任务就只能等着
  • 并行在时间上是重叠的,两个任务在同一时刻互不干扰的同时执行。
  • 并发允许两个任务彼此干扰。统一时间点、只有一个任务运行,交替执行。

        多线程三大特性:

        1.原子性      关键字:synchronized

        原子性是指在一个操作中cpu不可以在中途暂停然后再调度,即不被中断操作,要不全部执行完成,要不都不执行。

        2.可见性      关键字:volatile、synchronized、final

        当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

        3.有序性      关键字:volatile、synchronized

        虚拟机在进行代码编译时,对于那些改变顺序之后不会对最终结果造成影响的代码,虚拟机不一定会按照我们写的代码的顺序来执行,有可能将他们重排序。实际上,对于有些代码进行重排序之后,虽然对变量的值没有造成影响,但有可能会出现线程安全问题。

        总结:        

         synchronized关键字同时满足多线程三个特性,但是volatile关键字不满足原子性。在某些情况下,volatile的同步机制的性能确实要优于锁(使用synchronized关键字或java.util.concurrent包里面的锁),因为volatile的总开销要比锁低。我们判断使用volatile还是synchronized加锁的唯一依据就是volatile的语义能否满足使用的场景(原子性)。

5.线程通信的三种方式:

        1.wait()、notify()、notifyAll()

        线程之间采用synchronized来保证线程安全时,可以用Object类下的wait()、notify()、notifyAll()来实现线程通信。原因是每个对象都拥有锁,所以让当前线程等待某个对象的锁,当然应该通过这个对象来操作。这三个方法都是本地方法,并且被final修饰,无法被重写。

        2.await()、signal()、signalAll()

        线程之间采用Lock接口来保证线程安全时,因为Condition依赖于Lock接口,则可以利用Condition接口下的await()、signal()、signalAll()来实现线程通信。

        3.BlockingQueue

        BlockingQueue具有一个特征:当生产者线程试图向BlockingQueue中放入元素时,如果该队列已满,则该线程被阻塞;当消费者线程试图从BlockingQueue中取出元素时,如果该队列已空,则该线程被阻塞。两个线程通过交替向BlockingQueue中放入元素、取出元素,即可很好地控制线程的通信。线程之间需要通信,最经典的场景就是生产者与消费者模型,而BlockingQueue就是针对该模型提供的解决方案。

6.多线程多通道处理:

        线程内多Channel通道处理IO流由Java NIO支持,NIO采用内存映射文件的方式来处理输入/输出,NIO将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样来访问文件了(这种方式模拟了操作系统上的虚拟内存的概念),通过这种方式来进行输入/输出比传统的输入/输出要快得多。

        Java NIO 由三个核心组件构成:Selector (选择器), Channel(通道) , Buffer (缓冲区)。 虽然NIO体系还是有其它组件,比如:PipeFileLock等 它们只是与三个组件结合实际使用类。

  • Java NIO中的Selector允许单线程处理多个 Channel,如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件例如有新连接进来,数据接收等。
  • Channel(通道):所有的IO在NIO中都从一个Channel开始,数据可以从Channel读到Buffer中,也可以从Buffer写到Channel中。Channel有好几种类型,其中比较常用的有FileChannel、DatagramChannel、SocketChannel、ServerSocketChannel等,这些通道涵盖了UDP和TCP网络IO以及文件IO。
  • Buffer (缓冲区):Buffer本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。Java NIO里关键的Buffer实现有CharBuffer、ByteBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer。这些Buffer覆盖了你能通过IO发送的基本数据类型,即byte、short、int、long、float、double、char。Buffer对象包含三个重要的属性,分别是capacity、position、limit,其中position和limit的含义取决于Buffer处在读模式还是写模式。但不管Buffer处在什么模式,capacity的含义总是一样的。
    • capacity:作为一个内存块,Buffer有个固定的最大值,就是capacity。Buffer只能写capacity个数据,一旦Buffer满了,需要将其清空才能继续写数据往里写数据。

    • position:当写数据到Buffer中时,position表示当前的位置。初始的position值为0。当一个数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity–1。当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0。当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。

    • limit:在写模式下,Buffer的limit表示最多能往Buffer里写多少数据,此时limit等于capacity。当切换Buffer到读模式时, limit表示你最多能读到多少数据,此时limit会被设置成写模式下的position值。

三者关联关系:

        一个线程对应一个selector, 一个selector 对应多个channel。 多个通道中可以相互切换,是根据事件event来决定使用那个channel。

优点:        

        NIO单线程处理多通道的好处,处理通道所需要的线程数更少。一个线程可以处理所有的通道。在操作系统层面,线程的上下文切换是成本非常高。每个线程都会对应操作系统的内存。因此,线程数越少越好。

缺点:

        但随着CPU技术突破,多核超线程出现,若使用单线程来处理,有点浪费cpu资源。

        channel是指可以向其写入数据或读取数据的对象。 类似于IO中的strem。但是所有数据的读写都由buffer来进行的,channel不进行任何处理。

        一个stream只能是InputStream或者OutputStream。但channel是双向的,channel打开后,即可向其写入数据,也可以同时读取数据。

  buffer本身就是一块内存,底层使用数组来实现。buffer非线程安全,因此,在多线程并发的环境下,当访问buffer时,需要做适当的线程控制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值