介绍
- 5提供,增加了并发常用工具类,包括线程池、异步、IO和轻量级任务框架。
提供可调的、灵活的线程池。还提供了设计用于多线程上下文中的Collection实现等。
Lock
协调访问共享对象机制,synchronized,volatile,lock。
- ReentrantLock实现了Lock,提供了与synchronized相同的互斥性和内存可见性,相对更灵活。
Synchronized 和 Lock 区别
- Synchronized 内置的Java关键字, Lock 是一个Java类
- Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁
- Synchronized 会自动释放锁,lock 必须要手动释放锁!如果不释放锁,死锁
- Synchronized 线程 1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下去;
- Synchronized 可重入锁,不可以中断的,非公平;Lock ,可重入锁,可以 判断锁,非公平(可以
自己设置);
synchronized
public class DemoTest {public static void main(String[] args) {Ticket ticket = new Ticket();new Thread(() -> { for (int i = 0; i < 40; i++) { ticket.sale(); } }).start();new Thread(() -> { for (int i = 0; i < 40; i++) { ticket.sale(); } }).start();new Thread(() -> { for (int i = 0; i < 40; i++) { ticket.sale(); } }).start();}}//资源类class Ticket{private int num = 30;public synchronized void sale(){if (num > 0 ){System.out.println(Thread.currentThread().getName()+"--买到了第"+ (num--)+"票,剩余"+ num);}}}
ReentrantLock
public class DemoTest {public static void main(String[] args) {Ticket ticket = new Ticket();new Thread(() -> { for (int i = 0; i < 40; i++) { ticket.sale(); } }).start();new Thread(() -> { for (int i = 0; i < 40; i++) { ticket.sale(); } }).start();new Thread(() -> { for (int i = 0; i < 40; i++) { ticket.sale(); } }).start();}}//资源类class Ticket{private int num = 30;Lock lock = new ReentrantLock();public void sale(){lock.lock();try{if (num > 0 ){System.out.println(Thread.currentThread().getName()+"--买到了第"+ (num--)+"票,剩余"+ num);}}catch (Exception e){e.printStackTrace();}finally {lock.unlock();}}}
生产消费
public class DemoTest {public static void main(String[] args) {Data data = new Data();new Thread(()->{for (int i = 0; i < 10; i++) {try {data.increment();}catch (InterruptedException e){e.printStackTrace();}}},"A").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {data.decrement();}catch (InterruptedException e){e.printStackTrace();}}},"B").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {data.increment();}catch (InterruptedException e){e.printStackTrace();}}},"C").start();new Thread(()->{for (int i = 0; i < 10; i++) {try {data.decrement();}catch (InterruptedException e){e.printStackTrace();}}},"D").start();}}class Data{private int num = 0;public synchronized void increment() throws InterruptedException {//生产while (num!=0){// 等下还没准备好this.wait();}num++;System.out.println(Thread.currentThread().getName()+"生产==>完成"+num);// 通知其他线程,+1准备好了this.notifyAll();}public synchronized void decrement() throws InterruptedException {//消费while (num==0){// 多线程if存在虚假唤醒,改为whilethis.wait();}num--;System.out.println(Thread.currentThread().getName()+"消费==>完成"+num);// 通知其他线程,-1准备好了this.notifyAll();}}
public class DemoTest {public static void main(String[] args) {Data data = new Data();new Thread(()->{for (int i = 0; i < 10; i++) {data.increment();}},"A").start();new Thread(()->{for (int i = 0; i < 10; i++) {data.decrement();}},"B").start();new Thread(()->{for (int i = 0; i < 10; i++) {data.increment();}},"C").start();new Thread(()->{for (int i = 0; i < 10; i++) {data.decrement();}},"D").start();}}class Data{private int num = 0;Lock lock = new ReentrantLock();Condition condition = lock.newCondition();public void increment() {lock.lock();try {while (num!=0){condition.await();}num++;System.out.println(Thread.currentThread().getName()+"生产==>"+num);condition.signalAll();//通知其他线程,我好了。}catch (Exception e){e.printStackTrace();}finally {lock.unlock();}}public void decrement() {lock.lock();try {while (num==0){condition.await();//赶紧做}num--;System.out.println(Thread.currentThread().getName()+"消费==>"+num);condition.signalAll();//我吃完了}catch (Exception e){e.printStackTrace();}finally {lock.unlock();}}}
线程八锁
一个对象里面如果有多个synchronized方法,某一个时刻内,只要一个线程去调用
其中的一个synchronized方法了,其它的线程都只能等待,换句话说,某一个时刻
内,只能有唯一一个线程去访问这些synchronized方法
锁的是当前对象this,被锁定后,其它的线程都不能进入到当前对象的其它的
synchronized方法
加个普通方法后发现和同步锁无关
换成两个对象后,不是同一把锁了,情况立刻变化。
都换成静态同步方法后,情况又变化
所有的非静态同步方法用的都是同一把锁——实例对象本身,也就是说如果一个实
例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获
取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实
例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非
静态同步方法释放锁就可以获取他们自己的锁。
所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对
象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个
静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取
锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同
步方法之间,只要它们同一个类的实例对象!
Callable
依赖于FutureTask,FutureTask 也可用作闭锁
辅助类
CountDownLatch
- CyclicBarrier
-
读写锁(独占共享锁)
更细的控制
public class DemoTest {public static void main(String[] args) throws ExecutionException, InterruptedException {MyLock myLock = new MyLock();for (int i = 0; i < 5; i++) {final int temp = i;new Thread(()->{myLock.put(temp+"",temp+"");},String.valueOf(i)).start();}for (int i = 0; i < 5; i++) {final int temp = i;new Thread(()->{myLock.get(temp+"");},String.valueOf(i)).start();}}}class MyLock{private volatile Map<String,Object> map = new HashMap<>();public void put(String key, Object value){System.out.println(Thread.currentThread().getName()+"写入"+key);Object o = map.put(key,value);System.out.println(Thread.currentThread().getName()+"写入OK");}public void get(String key){System.out.println(Thread.currentThread().getName()+"读取"+key);Object o = map.get(key);System.out.println(Thread.currentThread().getName()+"读取OK");}}
