介绍

  • 5提供,增加了并发常用工具类,包括线程池、异步、IO和轻量级任务框架。
  • 提供可调的、灵活的线程池。还提供了设计用于多线程上下文中的Collection实现等。

    Lock

  • 协调访问共享对象机制,synchronized,volatile,lock。

  • ReentrantLock实现了Lock,提供了与synchronized相同的互斥性和内存可见性,相对更灵活。

    Synchronized 和 Lock 区别

  1. Synchronized 内置的Java关键字, Lock 是一个Java类
  2. Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁
  3. Synchronized 会自动释放锁,lock 必须要手动释放锁!如果不释放锁,死锁
  4. Synchronized 线程 1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下去;
  5. Synchronized 可重入锁,不可以中断的,非公平;Lock ,可重入锁,可以 判断锁,非公平(可以

自己设置);

  1. Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码!

    例子

  • synchronized

    1. public class DemoTest {
    2. public static void main(String[] args) {
    3. Ticket ticket = new Ticket();
    4. new Thread(() -> { for (int i = 0; i < 40; i++) { ticket.sale(); } }).start();
    5. new Thread(() -> { for (int i = 0; i < 40; i++) { ticket.sale(); } }).start();
    6. new Thread(() -> { for (int i = 0; i < 40; i++) { ticket.sale(); } }).start();
    7. }
    8. }
    9. //资源类
    10. class Ticket{
    11. private int num = 30;
    12. public synchronized void sale(){
    13. if (num > 0 ){
    14. System.out.println(Thread.currentThread().getName()+"--买到了第"+ (num--)+"票,剩余"+ num);
    15. }
    16. }
    17. }
  • ReentrantLock

    1. public class DemoTest {
    2. public static void main(String[] args) {
    3. Ticket ticket = new Ticket();
    4. new Thread(() -> { for (int i = 0; i < 40; i++) { ticket.sale(); } }).start();
    5. new Thread(() -> { for (int i = 0; i < 40; i++) { ticket.sale(); } }).start();
    6. new Thread(() -> { for (int i = 0; i < 40; i++) { ticket.sale(); } }).start();
    7. }
    8. }
    9. //资源类
    10. class Ticket{
    11. private int num = 30;
    12. Lock lock = new ReentrantLock();
    13. public void sale(){
    14. lock.lock();
    15. try{
    16. if (num > 0 ){
    17. System.out.println(Thread.currentThread().getName()+"--买到了第"+ (num--)+"票,剩余"+ num);
    18. }
    19. }catch (Exception e){
    20. e.printStackTrace();
    21. }finally {
    22. lock.unlock();
    23. }
    24. }
    25. }
  • 生产消费

    1. public class DemoTest {
    2. public static void main(String[] args) {
    3. Data data = new Data();
    4. new Thread(()->{
    5. for (int i = 0; i < 10; i++) {
    6. try {
    7. data.increment();
    8. }catch (InterruptedException e){
    9. e.printStackTrace();
    10. }
    11. }
    12. },"A").start();
    13. new Thread(()->{
    14. for (int i = 0; i < 10; i++) {
    15. try {
    16. data.decrement();
    17. }catch (InterruptedException e){
    18. e.printStackTrace();
    19. }
    20. }
    21. },"B").start();
    22. new Thread(()->{
    23. for (int i = 0; i < 10; i++) {
    24. try {
    25. data.increment();
    26. }catch (InterruptedException e){
    27. e.printStackTrace();
    28. }
    29. }
    30. },"C").start();
    31. new Thread(()->{
    32. for (int i = 0; i < 10; i++) {
    33. try {
    34. data.decrement();
    35. }catch (InterruptedException e){
    36. e.printStackTrace();
    37. }
    38. }
    39. },"D").start();
    40. }
    41. }
    42. class Data{
    43. private int num = 0;
    44. public synchronized void increment() throws InterruptedException {//生产
    45. while (num!=0){
    46. // 等下还没准备好
    47. this.wait();
    48. }
    49. num++;
    50. System.out.println(Thread.currentThread().getName()+"生产==>完成"+num);
    51. // 通知其他线程,+1准备好了
    52. this.notifyAll();
    53. }
    54. public synchronized void decrement() throws InterruptedException {//消费
    55. while (num==0){
    56. // 多线程if存在虚假唤醒,改为while
    57. this.wait();
    58. }
    59. num--;
    60. System.out.println(Thread.currentThread().getName()+"消费==>完成"+num);
    61. // 通知其他线程,-1准备好了
    62. this.notifyAll();
    63. }
    64. }
    1. public class DemoTest {
    2. public static void main(String[] args) {
    3. Data data = new Data();
    4. new Thread(()->{
    5. for (int i = 0; i < 10; i++) {
    6. data.increment();
    7. }
    8. },"A").start();
    9. new Thread(()->{
    10. for (int i = 0; i < 10; i++) {
    11. data.decrement();
    12. }
    13. },"B").start();
    14. new Thread(()->{
    15. for (int i = 0; i < 10; i++) {
    16. data.increment();
    17. }
    18. },"C").start();
    19. new Thread(()->{
    20. for (int i = 0; i < 10; i++) {
    21. data.decrement();
    22. }
    23. },"D").start();
    24. }
    25. }
    26. class Data{
    27. private int num = 0;
    28. Lock lock = new ReentrantLock();
    29. Condition condition = lock.newCondition();
    30. public void increment() {
    31. lock.lock();
    32. try {
    33. while (num!=0){
    34. condition.await();
    35. }
    36. num++;
    37. System.out.println(Thread.currentThread().getName()+"生产==>"+num);
    38. condition.signalAll();//通知其他线程,我好了。
    39. }catch (Exception e){
    40. e.printStackTrace();
    41. }finally {
    42. lock.unlock();
    43. }
    44. }
    45. public void decrement() {
    46. lock.lock();
    47. try {
    48. while (num==0){
    49. condition.await();//赶紧做
    50. }
    51. num--;
    52. System.out.println(Thread.currentThread().getName()+"消费==>"+num);
    53. condition.signalAll();//我吃完了
    54. }catch (Exception e){
    55. e.printStackTrace();
    56. }finally {
    57. lock.unlock();
    58. }
    59. }
    60. }

    线程八锁

  • 一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用

其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻
内,只能有唯一一个线程去访问这些synchronized方法
锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的
synchronized方法
加个普通方法后发现和同步锁无关
换成两个对象后,不是同一把锁了,情况立刻变化。
都换成静态同步方法后,情况又变化
所有的非静态同步方法用的都是同一把锁——实例对象本身,也就是说如果一个实
例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获
取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实
例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非
静态同步方法释放锁就可以获取他们自己的锁。
所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对
象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个
静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取
锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同
步方法之间,只要它们同一个类的实例对象!

Callable

  • 依赖于FutureTask,FutureTask 也可用作闭锁

    辅助类

  • CountDownLatch

  • CyclicBarrier
  • Semaphore

    读写锁(独占共享锁)

  • 更细的控制

    1. public class DemoTest {
    2. public static void main(String[] args) throws ExecutionException, InterruptedException {
    3. MyLock myLock = new MyLock();
    4. for (int i = 0; i < 5; i++) {
    5. final int temp = i;
    6. new Thread(()->{myLock.put(temp+"",temp+"");},String.valueOf(i)).start();
    7. }
    8. for (int i = 0; i < 5; i++) {
    9. final int temp = i;
    10. new Thread(()->{myLock.get(temp+"");},String.valueOf(i)).start();
    11. }
    12. }
    13. }
    14. class MyLock{
    15. private volatile Map<String,Object> map = new HashMap<>();
    16. public void put(String key, Object value){
    17. System.out.println(Thread.currentThread().getName()+"写入"+key);
    18. Object o = map.put(key,value);
    19. System.out.println(Thread.currentThread().getName()+"写入OK");
    20. }
    21. public void get(String key){
    22. System.out.println(Thread.currentThread().getName()+"读取"+key);
    23. Object o = map.get(key);
    24. System.out.println(Thread.currentThread().getName()+"读取OK");
    25. }
    26. }