java并发编程之美——基础篇

一、什么是线程

线程是进程的一个实体,线程不会独立存在。一个进程最少包含一个线程。线程是cup分配的基本单位。

java并发编程之美——基础篇

 

 

 多个线程共享进程的堆和方法区,每个线程都有自己独立的程序计数器和栈。

二、线程的创建和运行

线程创建有三种方式:继承Thread、实现runnable接口、使用FutureTask方式。

区别:

1.继承thread方式的好处是获取当前线程直接调用Thread.currentThread()方法获取。缺点是:java只支持单继承,继承Thread后就不能继承其他class,可扩展性差。其次:线程任务和代码没有分离,当多个线程执行一样的任务时需要多份任务代码。

2.runnable接口方式使线程任务和代码相分离,更符合面向对象的思想。

3.FutureTask方式可以使线程执行有返回值。

三、线程与等待

1.wait() 

线程调用wait()方法,该线程会被阻塞,直到其他线程调用notify(),notifyAll()方法或者interrupt()方法,该线程抛出InterruptException异常并返回。

另外,调用wait()的线程需要事先获取该对象的监视器锁,否则抛出异常。

需要注意:一个线程可以在吗诶呦调用notify()或notifyAll()时被唤醒,叫做虚假唤醒,所以需要不断的去测试线程被唤醒的条件是否满足,不满足则继续wait()

synchronized(obj) {

  while(唤醒条件不满足) {

    obj.wait();

  }

}

2.wait(long timeout)

多了一个超时参数,如果线程没有在timeout时间内被唤醒,该线程会因为超时而返回。

3.wait(long timeout,int nanos)

内部调用wait(long timeout)

4.notify()

5.notifyAll()唤醒由于调用wait()被阻塞的线程。

6.程执行终止的join()方法

该方法会再线程执行完之前一直被阻塞。

7.sleep()

线程会暂时让出指定时间的执行权,但是该线程所持有的监视器资源还是不会让出

8.yield()

一个线程调用yeild方法时,当前线程会让出cup使用权,交给线程就绪队列中一个优先级最高的线程。

9.线程中断。

void interrupt():中断线程,线程如果因为调用wait(),sleep(),join()方法被阻塞时调用会抛出InterruptException异常。

boolean isInterrupted():检测当前线程是否被中断。

boolean interrupted():检测当前线程是否被中断。与isInterrupted()不同的是,该方法如果发现当前线程被中断,则会清除中断标志。并且,该线程与interrupt()不同的是,该线程调用的是当前线程的中断标志。

四、线程上下文切换

cup资源分配是基于时间片轮转的策略。也就是给每个线程分配一个时间片,线程在时间片内占用cup执行任务。时间片轮转就需要线程切换。

线程切换的时机有:当前线程的cup时间片使用完处于就绪状态时,当前线程被其他线程中断时。

五、线程死锁

1.什么是线程死锁?

死锁是指多个线程互相持有对方需要的监视器资源而造成相互等待而无法继续运行下去。

产生死锁的四大条件:(1)互斥条件,一个资源在一个时间只能由一个线程占用。(2)请求并持有条件:一个线程已经持有一个资源,又提出请求新的资源(3)不可剥夺条件:该线程获取到的资源在自己使用完之前不能被其他线程占用。

(4)环路等待条件:指在发生死锁时吗,线程——资源之间形成环形链。

2.如何避免线程死锁?

需要破坏四大条件的一个或多个为出发点。只有请求持有和环路等待是可以被破坏的。

解决方法:多个线程资源有序请求持有。

六:守护线程和用户线程

java线程分为两大类: deamon线程和user线程。user线程结束jvm就会退出。有user线程还没结束,jvm進程就不会退出

七、ThreadLocal

多线程对同一个共享变量访问时特别容易出现并发问题,为了保证线程安全,一般使用者在访问共享变量时需要进行适当地同步。

ThreadLocal会为每个线程创建一个副本。每个线程都访问自己的副本。

实现原理:

Thread类中有一个threadLocals和inheritableThreadLocals,他们都是ThreadLocalMap类型的变量。每个线程调用set()都会在threadLocals添加一条key-value,

ThreadLocal不支持继承性。

InheritableThreadLocal支持继承性。

八、并发和并行。

并发是指同一个时间段内多个任务同时都在执行,并且都没有结束。并行指单位时间内多个任务同时在执行。并发的面向对象是线程,并行面向的是进程。

九、java*享变量的内存可见性问题

多核cup会有自己的控制器、运算器和一级缓存。还会有共享的多级缓存。

线程工作时,会从共享缓存复制到自己的缓存,处理完成后会写入到共享缓存。

十、sychronized关键字

sychronized是java提供的一种原子性内置锁,java中的每个对象都可以把它当做一个同步锁使用,这些java内置的使用者看不到的锁称为内置锁,也叫做监视器锁。

wait可以释放内置锁。内置锁是排他锁,当一个线程获取内置锁,其他线程就会被阻塞。

1.sychronized的内存语义

进入sychronized块,块内使用到的变量就不会从工作内存获取,而是从共享内存获取,退出sychronized就会把线程对共享内存的修改刷新到共享内存。

十一、volidate

(1)volidate关键字可以确保一个变量的更新会立刻对另外一个线程可见。

(2)禁止指令重排序

java内存模型允许编译器和cup对指令重排序以提高运行性能,并且只会对不存在数据依赖性的指令重排序。这样在多线程下会产生问题。

volidate可以禁止指令重排序。

 

上一篇:Codeforces Round #681 (Div. 1, based on VK Cup 2019-2020 - Final) C. Graph Transpositions


下一篇:CodeForecs 1270E Divide Points