介绍
- 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存在虚假唤醒,改为while
this.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");
}
}