Java并发

Java并发基础

2019-02-17  本文已影响0人  _Once1

并发基础


线程

表示一条单独的执行流,有自己自己单独的程序计数器和栈;

1.1 创建方法

1.2 基本属性

NEW:没有调用start的线程
RUNNABLE:调用start后,正在执行run方法并且没有阻塞的状态;注意:线程在运行或者具备运行条件,只是在等待操作系统调度
BLOCKED:线程在等待锁,视图进入同步块
WAITING: 在等待某个条件
TIMED_WAITING: 在等待超时
TERMINATED: 运行结束后的状态

1.3 基本方法

1.4 多线程可能存在的问题

1.5 优缺点


synchronized的理解

2.1 用法

可用于修饰类的:

synchronized修饰实例方法,保护的是当前的实例对象,即this;每一个对象都有一个锁和等待队列,同一时间,锁只能被一个线程所持有;具体执行synchronized实例方法的过程如下:
1) 尝试获得锁,若得到,则执行,否则,加入等待队列,阻塞并等待唤醒
2) 执行方法
3) 释放锁,如果等待队列有线程,则取一个并将其唤醒;注意,如果有多个等待线程,则唤醒哪一个是不一定的,不保证公平性

注意: synchronized关键字保护的是对象而不是具体的代码,理解这一点是很重要的。只要访问的是同一个对象的synchronized方法,即使是不同的代码,也会被保证同步顺序方法。
并且,只能保证加了synchronized修饰的方法同步执行,synchronized方法无法保证非synchronized方法被同时执行;因此,在保护变量时,需要在所有访问该变量的方法上加synchronized修饰。

2.2 特点

当使用synchronized时,需要特别注意修饰的对象是否是同一个,即是否使用了相同的锁;


线程间的协作

3.1 wait/notify

除了用于锁的等待队列, 线程还有另一个等待队列, 表示条件队列,用于线程间的协作。
当调用了wait之后,就会把当前线程加入条件队列并阻塞, 表示当前线程执行不下去了,需要等待一个条件,这个条件自己改变不了,需要其他线程改变,当其他线程改变了条件后,应该调用notify方法。

wait/notify方法只能在synchronized代码块内被调用,否则会抛异常。

wait的具体过程

  1. 把当前的线程加入条件队列,释放对象锁,阻塞等待,线程状态变为WAITING或者TIME_WAITING
  2. 等待时间到或者被其他线程调用notify/notifyAll从条件队列中移除,这时,需要重新竞争对象锁:
    a) 可以获得,线程状态变为RUNNABLE,从wait调用中返回
    b) 无法获得,该线程会加入对象锁等待队列,线程状态变为BLOCKED,获得锁后才会从wait调用中返回;

从wait调用中返回后,不代表其等待条件就一定成立,需要重新检查等待条件:

synchronized (obj) {
    while(条件不成立) {
        obj.wait();
    }
    // do sth
}

调用notify后,并不会释放对象锁,只有在包含notify的synchronized代码块执行结束后,等待的线程才会从wait调用中返回

总结:wait/notify被不同的线程调用,但是二者共享相同的锁和条件等待队列(即相同锁对象的synchronized代码块内),二者围绕一个共享的条件变量进行协作,这个变量是程序自己维护的,当不满足时,wait并进入条件等待队列,另一个线程修改了该条件变量并调用了notify,然后调用wait的线程被唤醒,该线程需要重新检查条件变量。在使用wait/notify时,需要明确协作的共享变量和条件是什么。

3.2 生产者/消费者模式

Java提供的阻塞队列有:

3.3 同时开始

其他线程都先wait,条件满足后notifyAll即可

3.4 等待结束

以未就绪线程数量为条件,一个线程就绪后,将条件-1,当条件为0时,notifyAll即可
Java提供了CountDownLatch用于这种情况

3.5 异步结果

Java提供的主要涉及到的是:

3.5 集合点

当所有线程都执行结束后,到达集合点,交换数据并进行下一步动作;这种和等待结束是类似的;
Java提供了CyclicBarrier


线程的中断

4.1 中断

主要用到的机制是中断,下面来看下中断。
中断并不是强迫终止一个线程,它是一种协作机制,是传递给线程一个取消信号,但何时退出是由线程来决定的。
Java主要提供了下面几个方法:

4.2 线程对中断的反应

根据线程当前的状态:调用interrupt()后的变化如下:

4.3 如何取消/关闭线程

如果不清楚线程在做什么,不要贸然使用interrupt方法;
具体的取消方法可以参考原生实现:Future接口的cancle()、ExecutorService的shutdown(),shutdownNow()等

上一篇下一篇

猜你喜欢

热点阅读