Synchronized和Lock的区别
1、Synchronized内置的java关键字,Lock是一个Java类
2、Synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁
3、Synchronized会自动释放锁,Lock锁并需要手动释放锁,否则会死锁
4、Synchronized 线程1(获得锁,阻塞)、线程2(等待,死等) Lock锁就不一定会等待下去
5、Synchronized,可重入锁,不可以中断的,非公平,Lock,可重入锁,可以判断锁,非公平(可以自己设置)
6、Synchronized 适合锁少量的代码同步问题,Lock适合锁大量的同步代码
1、生产者和消费者问题
面试的:单例模式、排序模式、生产者消费者模式、死锁
生产者消费者模式
package com.bjw.pc;
import java.sql.Date;
/*
* 线程之间的通信问题,生产者和消费者问题! 等待唤醒,通知唤醒
* 线程交替执行A B 操作同一个变量 num = 0
* A num+1
* B num-1
* */
public class A {
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();
}
}
// 等待,业务,通知
class Data{ //数字 资源类
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
if(number != 0) {
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程,我+1完毕
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
if(number == 0) {
//等待
this.wait();
}
number--;
//通知其他线程,我-1完毕了
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notifyAll();
}
}
问题存在, A B C D 四个线程 !
虚假唤醒 应把 if改为while
package com.bjw.pc;
import java.sql.Date;
/*
* 线程之间的通信问题,生产者和消费者问题! 等待唤醒,通知唤醒
* 线程交替执行A B 操作同一个变量 num = 0
* A num+1
* B num-1
* */
public class A {
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();
}
}
// 等待,业务,通知
class Data{ //数字 资源类
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
while(number != 0) {
//等待
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程,我+1完毕
this.notifyAll();
}
//-1
public synchronized void decrement() throws InterruptedException {
while(number == 0) {
//等待
this.wait();
}
number--;
//通知其他线程,我-1完毕了
System.out.println(Thread.currentThread().getName()+"=>"+number);
this.notifyAll();
}
}
JUC版的生产者和消费者问题
通过Lock找到找到Condition
package com.bjw.pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class B {
public static void main(String[] args) {
Data2 data = new Data2();
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 Data2{ //数字 资源类
private int number = 0;
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
//+1
public synchronized void increment() throws InterruptedException {
lock.lock();
try {
//业务代码
while(number != 0) {
//等待
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName()+"=>"+number);
//通知其他线程,我+1完毕了
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//-1
public synchronized void decrement() throws InterruptedException {
lock.lock();
try {
//业务代码
while(number == 0) {
//等待
condition.await();
}
number--;
//通知其他线程,我-1完毕了
System.out.println(Thread.currentThread().getName()+"=>"+number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Condition的优势
精准的通知和唤醒线程
package com.bjw.pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
* A执行完调用B
* B执行完调用C
* C执行完调用A
* */
public class C {
public static void main(String[] args) {
Data3 data = new Data3();
new Thread(()->{
for(int i = 0; i < 10; i++) {
data.printA();
}
},"A").start();
new Thread(()->{
for(int i = 0; i < 10; i++) {
data.printB();
}
},"B").start();
new Thread(()->{
for(int i = 0; i < 10; i++) {
data.printC();
}
},"C").start();
}
}
class Data3 { //资源类Lock
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int number = 1; // 1A 2B 3C
public void printA() {
lock.lock();
try {
//业务,判断->执行->通知
while (number != 1) {
//等待
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"=>A");
//唤醒,唤醒指定的人B
number = 2;
condition2.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
while (number != 2) {
condition2.await();
}
System.out.println(Thread.currentThread().getName()+"=>B");
number = 3;
condition3.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
while (number != 3) {
condition3.await();
}
System.out.println(Thread.currentThread().getName()+"=>C");
number = 1;
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
2、8锁现象
如何判断锁的是谁!锁的对象是谁
对象,class
package com.bjw.lock8;
import java.util.concurrent.TimeUnit;
/*
* 8锁就是关于锁的8个问题
* 1、标准情况下,两个线程先打印 发短信还是打电话?
* 2、发短信sleep了4秒,两个线程是 先发短信还是打电话
*
*
* */
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
//锁的存在
new Thread(()->{
phone.sendSms();
},"A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
//synchronized 锁的对象是方法的调用者!
//两个方法用的是同一个锁,谁先拿到谁执行
public synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendSms");
}
public synchronized void call() {
System.out.println("call");
}
}
package com.bjw.lock8;
import java.util.concurrent.TimeUnit;
/*
* 8锁就是关于锁的8个问题
* 3、增加了一个普通方法后,发短信还是hello?普通方法
* 4、两个对象,两个同步方法 //打电话
*
* */
public class Test2 {
public static void main(String[] args) {
//两个对象。两个调用者,两把锁
Phone2 phone1 = new Phone2();
Phone2 phone2 = new Phone2();
//锁的存在
new Thread(()->{
phone1.sendSms();
},"A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone2{
//synchronized 锁的对象是方法的调用者!
//两个方法用的是同一个锁,谁先拿到谁执行
public synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendSms");
}
public synchronized void call() {
System.out.println("call");
}
//这里没有锁!不受锁的影响
public void hello() {
System.out.println("hello");
}
}
package com.bjw.lock8;
import java.util.concurrent.TimeUnit;
/*
* 5、增加两个静态同步方法,只有一个对象 发短信
* 6、两个对象!增加两个静态的同步方法 发短信
* */
public class Test3 {
public static void main(String[] args) {
//两个对象的class类模板只有一个 static 锁的是 class
Phone3 phone1 = new Phone3();
Phone3 phone2 = new Phone3();
//锁的存在
new Thread(() -> {
phone1.sendSms();
}, "A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
new Thread(() -> {
phone2.call();
}, "B").start();
}
}
//Phone3唯一的一个class对象
class Phone3{
//synchronized 锁的对象是方法的调用者!
//static 静态方法
//类一加载就有了!Class模板,锁的是class
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendSms");
}
public static synchronized void call() {
System.out.println("call");
}
}
package com.bjw.lock8;
import java.util.concurrent.TimeUnit;
/*
* 7、一个普通同步方法,一个静态同步方法,只有一个对象 打电话
* 8、一个普通同步方法,一个静态同步方法,两个对象 打电话
* */
public class Test4 {
public static void main(String[] args) {
//两个对象的class类模板只有一个 static 锁的是 class
Phone4 phone = new Phone4();
/*Phone4 phone2 = new Phone4();*/
//锁的存在
new Thread(() -> {
phone.sendSms();
}, "A").start();
//捕获
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
new Thread(() -> {
phone.call();
}, "B").start();
}
}
//Phone3唯一的一个class对象
class Phone4{
//静态同步方法,锁的是class类模板
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendSms");
}
//普通同步方法,锁的是对象
public synchronized void call() {
System.out.println("call");
}
}
小结
new this 具体的一个手机
static class 唯一的一个模板