常见的锁 Synchronized 和 Lock
线程不安全 线程安全
List CopyOnWriteList
Map ConcurrentHashMap
Set CopyOnWriteSet
从CopyonWriteList的底层看到 add方法 是添加了锁的
public boolean add(E e) {
synchronized(this.lock) {
Object[] es = this.getArray();
int len = es.length;
es = Arrays.copyOf(es, len + 1);
es[len] = e;
this.setArray(es);
return true;
}
}
Synchronized锁
公用的变量是谁锁的就是谁,这里银行账户是公用的是银行账户,锁的就是Synchronized(账户)
public class UnsafeBank {
public static void main(String[] args) {
Account account = new Account(100,"结婚基金");
Drawing you = new Drawing(account,50,"你");
Drawing girlfriend = new Drawing(account,80,"你老婆");
you.start();
girlfriend.start();
}
}
class Account {
int money;
String name;
public Account(int money, String name) {
this.money = money;
this.name = name;
}
}
class Drawing extends Thread {
Account account ;
int drawingmoney;
int nowmoney;
public Drawing(Account account,int drawingMoney,String name) {
this.account = account;
this.drawingmoney = drawingMoney;
}
@Override
public void run() {
synchronized (account) {
if ( account.money - drawingmoney <0) {
System.out.println(this.getName()+" money is not enough");
return;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
account.money = account.money - drawingmoney;
System.out.println(account.name +"余额为:" + account.money);
}
}
}
锁Synchronize 可以加到公共变量上面,也可以去锁某个方法
Lock锁 有三种实现,ReEntranceLock, ReadLock, WriteLock()
卖票问题——synchronize
import java.util.concurrent.TimeUnit;
public class SaleTicket_sunchronized {
public static void main(String[] args) {
Ticket2 ticket2 = new Ticket2();
new Thread(()->{
for(int i=0;i<40;i++) {
ticket2.sales();
}
},"a").start();
new Thread(()->{
for(int i=0;i<40;i++) {
ticket2.sales();
}
},"b").start();
new Thread(()->{
for(int i=0;i<40;i++) {
ticket2.sales();
}
},"c").start();
}
}
class Ticket2 {
private Integer num = 100;
// 锁方法
// public synchronized void sales() {
// if(num > 0) {
// System.out.println(Thread.currentThread().getName()+"剩余票数量"+num--);
// }
// try {
// TimeUnit.MILLISECONDS.sleep(50);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
public void sales() {
// 锁代码块
// 和 Synchronized ( Ticket.class 是一样的)
synchronized (this) {
if(num > 0) {
System.out.println(Thread.currentThread().getName()+"剩余票数量"+num--);
}
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Lock锁
package com.pq.multiThread.syn;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
// synchronized 可以锁代码块,可以锁方法 锁代码块的时候里面的参数要保证唯一
public class SaleTicket_lock {
public static void main(String[] args) {
Ticket1 ticket1 = new Ticket1();
new Thread(()->{
for(int i=0;i<100;i++) {
ticket1.sale();
}
},"a").start();
new Thread(()->{
for(int i=0;i<100;i++) {
ticket1.sale();
}
},"b").start();
new Thread(()->{
for(int i=0;i<100;i++) {
ticket1.sale();
}
},"c").start();
}
}
class Ticket1 {
private Integer count = 100;
Lock lock = new ReentrantLock();
public void sale() {
lock.lock();
try {
if (count > 0) {
System.out.println(Thread.currentThread().getName()+count--+"张票。。");
}
TimeUnit.MILLISECONDS.sleep(100);
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
synchronize 和 Lock的区别
//总结二者区别
// synchronized 是内置关键字 ## Lock 是对象
//synchronized 适合少量代码块,方法 ## Lock适合锁大量代码
// 无法判断锁的状态 ## 可以判断锁的状态
// 会自动释放锁 ## 需要手动释放锁,否则会死锁
// 锁后别的线程会傻傻等待 ## Lock锁不会一直等待下去
// 可重入锁 非公平 ## 可重入锁 默认非公平(true)
生产者消费者问题
生产者消费者问题 涉及线程之间的通信问题
synchronized 主要使用wait(), notifyAll() 进行等待和唤醒
public class ConsumerAndProduct_syn {
public static void main(String[] args) {
Pool1 pool1 = new Pool1();
new Thread(()->{
for (int i=0;i<10;i++) {
try {
pool1.increament1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"a").start();
new Thread(()->{
for (int i=0;i<10;i++) {
try {
pool1.decreament1();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"b").start();
}
}
//
class Pool1 {
private int num1=1;
public synchronized void increament1() throws InterruptedException {
// 我设定池内数量最多为2 ,所以是和2进行比较,这个值是可以改的
while (num1 >=2) {
//等待 保持所持有的锁
this.wait();
}
System.out.println("生产了一个 池内数量为 "+ (++num1));
//唤醒别的线程
this.notifyAll();
}
public synchronized void decreament1() throws InterruptedException {
// 为0 的时候就不能再消费了
while (num1 < 1) {
this.wait();
}
System.out.println("消费了一个 池内数量为 "+ (--num1));
this.notifyAll();
}
}
JUC 的Lock方法
package com.pq.multiThread.consumer;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConsumerAndProduct_juc {
public static void main(String[] args) {
Pool2 pool2 = new Pool2();
new Thread(()->{
for(int i=0;i<10;i++) {
try {
pool2.increament2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for(int i=0;i<10;i++) {
try {
pool2.decreament2();
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for(int i=0;i<10;i++) {
try {
pool2.decreament2();
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
}
}
class Pool2 {
private int num1=1;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void increament2() throws InterruptedException {
// 我设定池内数量最多为2 ,所以是和2进行比较,这个值是可以改的
lock.lock();
try{
while (num1 >= 2) {
condition.await();
}
System.out.println(Thread.currentThread().getName()+ "生产了一个 池内数量为 "+(++num1));
condition.signalAll();
} catch (Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decreament2() throws InterruptedException {
lock.lock();
try{
while (num1 < 1) {
condition.await();
}
System.out.println(Thread.currentThread().getName()+ "消费了一个 池内数量为 "+(--num1));
condition.signalAll();
} catch (Exception e){
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Lock并不是简单的对synchronized的方法进行了覆盖,Lock可以做到精准唤醒线程,利用的是condition.signal()