并发编程(一)多线程基础篇

1什么是线程:

        现代操作系统调度的最小单元是线程,

2. 为什么要使用多线程

       (1)更多的处理器核心(一个线程在一个时刻只能运行在一个处理器核心上)

        (2)更快的响应时间

        (3)景:可以使用多线程技术,即将数据一致性不强的操作派发给其他线程处理(也可以使用消息队列),如生成订单快照、发送邮件等。这样做的好处是响应用户请求的线程能够尽可能快地处理完成,缩短了响应时间,提升了用户体验)

3.线程优先级

线程的调度采用时间片的形式,当线程的时间片用完了就会发生线程调度,并等待着下次分配。线程分配到的时间片多少也就决定了线程使用处理器资源的多少,而线程优先级就是决定线程需要多或者少分配一些处理器资源的线程属性

 Java线程有优先级,优先级高的线程会获得较多的运行机会(并不是个优先级高就一定执行)

 Java线程的优先级用整数表示,取值范围是1~10,Thread类有以下三个静态常量:

static int MAX_PRIORITY

          线程可以具有的最高优先级,取值为10。

static int MIN_PRIORITY

          线程可以具有的最低优先级,取值为1。

static int NORM_PRIORITY

          分配给线程的默认优先级,取值为5。

Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。

 

4.线程状态、

状态名称

说明

新建状态(New)

新创建了一个线程对象

就绪状态(Runnable)

线程对象创建后,其他线程调用了该对象的start()方法。

运行状态(Running)

就绪状态的线程获取了CPU,执行程序代码。

阻塞状态(Blocked)

阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。

死亡状态(Dead)

线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

4.1线程的状态图:


阻塞的情况分三种:

(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。(wait会释放持有的锁)

(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。

(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。(注意,sleep是不会释放持有的锁)

 4.2并发编程艺术中的状态图:


超时等待状:态相当于在等待状态的基础上增加了超时限制,也就是超时时间到达时将会返回到运行状态。

4.3volatile和synchronized关键字(JVM内存模型中讲解过)

关键字volatile可以用来修饰字段(成员变量),就是告知程序任何对该变量的访问均需要 从共享内存中获取,而对它的改变必须同步刷新回共享内存,它能保证所有线程对变量访问的可见性。

关键字synchronized可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程 在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性。

4.4对象、对象的监视器、同步队列和执行线程之间的关系。

任意一个对象都拥有自己的监视器,当这个对象由同步块或者这个对象的同步方法调用时,执行方法的线程必须先获取到该对象的监视器才能进入同步块或者同步方法,而没有获取到监视器(执行该方法)的线程将会被阻塞在同步块和同步方法的入口处,进入BLOCKED 状态。

 

4.5等待/通知机制

等待/通知机制,是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B 调用了对象O的notify()或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而执行后续操作。

 

注意:

1)使用wait()notify()notifyAll()时需要先对调用对象加锁。

2)调用wait()方法后,线程状态由RUNNING变为WAITING,并将当前线程放置到对象的等待队列。

3notify()notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify() notifAll()的线程释放锁之后,等待线程才有机会从wait()返回。

 4notify()方法将等待队列中的一个等待线程从等待队列中移到同步队列中,而notifyAll() 方法则是将等待队列中所有的线程全部移到同步队列,被移动的线程状态由WAITING变为 BLOCKED

5)从wait()方法返回的前提是获得了调用对象的锁。

WaitThread首先获取了对象的锁,然后调用对象的wait()方法,从而放弃了锁并进入了对象的等待队列WaitQueue中,进入等待状态。由于WaitThread释放了对象的锁, NotifyThread随后获取了对象的锁,并调用对象的notify()方法,将WaitThread从WaitQueue移到 SynchronizedQueue中,此时WaitThread的状态变为阻塞状态。NotifyThread释放了锁之后, WaitThread再次获取到锁并从wait()方法返回继续执行。

4.6notify和notifyAll的区别

notifyAll调用后,会将全部线程由等待队列移到同步锁队列,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在同步锁队列等待锁被释放后再次参与竞争。而notify只会唤醒一个线程。所以notify可能会导致死锁,而notifyAll则不会死锁

 

4.7Thread.join()的使用

 

如果一个线程A执行了thread.join()语句,其含义是:当前线程A等待thread线程终止之后才。

从thread.join()返回。线程Thread除了提供join()方法之外,还提供了join(longmillis)和join(longmillis,int nanos)两个具备超时特性的方法。这两个超时方法表示,如果线程thread在给定的超时时间里没有终止,那么将会从该超时方法中返回。

总结:Thread.join()可以控制线程的执行顺序。

4.8 ThreadLocal的使用

hreadLocal,即线程变量,是一个以ThreadLocal对象为键、任意对象为值的存储结构。

这个结构被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。可以通过set(T)方法来设置一个值,在当前线程下再通过get()方法获取到原先设置的值。



猜你喜欢

转载自blog.csdn.net/zpoison/article/details/80940470
今日推荐