JUC是java.util.concurrent工具包的简称,是一个处理线的工具包
进程与线程
进程:程序的运行过程
线程:操作系统进行运行调度的最小单位,被包含在进程中,是进程中运行的实际单位
进程与线程的关系,比如电脑开了一个文档,文档运行就是进程,文档中打字,查找,等等操作就是线程。
wait/sleep的区别
来自不同的类:wait=>Object sleep=>Thread
关于锁的释放:wait会释放,sleep抱着锁睡觉,不会释放
使用范围不同:wait必须在同步代码块中,sleep哪都能睡
是否需要捕获异常:wait不需要捕获异常,sleep需要捕获异常
JUC源码得出他们都需要捕获异常
sychronized 和 lock
关于线程同步,需要牢牢记住的第一点是:线程同步就是线程排队。同步就是排队。线程同步的目的就是避免线程“同步”执行。这可真是个无聊的绕口令。
关于线程同步,需要牢牢记住的第二点是 “共享”这两个字。只有共享资源的读写访问才需要同步。如果不是共享资源,那么就根本没有同步的必要。
关于线程同步,需要牢牢记住的第三点是,只有“变量”才需要同步访问。如果共享的资源是固定不变的,那么就相当于“常量”,线程同时读取常量也不需要同步。至少一个线程修改共享资源,这样的情况下,线程之间就需要同步。
关于线程同步,需要牢牢记住的第四点是:多个线程访问共享资源的代码有可能是同一份代码,也有可能是不同的代码;无论是否执行同一份代码,只要这些线程的代码访问同一份可变的共享资源,这些线程之间就需要同步。
sychronized和lock的区别
Synchronized是关键字,lock是类
Synchronized会自动释放锁,lock必须手动释放锁,否则会发生死锁
Synchronized无法判断锁的状态,lock可以判断是否获得锁
比如A线程(获得锁),阻塞,Synchronized的话B线程会傻傻的等待;lock锁B线程不一定会一直等待
Synchronized 可重入锁 ,不可中断,非公平;lock 可重入锁,可以判断锁状态,默认非公平,可修改
Synchronized 适合少量线程同步问题,lock适合大量同步代码
消费者与生产者
传统的生产者与消费者问题
package com.boom.example.demo.aa;
public class pc {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
for(int i=1;i<=10;i++){
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for(int i=1;i<=10;i++){
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for(int i=1;i<=10;i++){
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"c").start();
new Thread(()->{
for(int i=1;i<=10;i++){
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"d").start();
}
}
//判断等待,业务,通知
class Data{
private int number = 0;
public synchronized void increment() throws InterruptedException {
//如果是if会虚假唤醒
while (number !=0){
this.wait();
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
while (number == 0){
this.wait();
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
this.notifyAll();
}
}
lock版的
class Data{
private int number = 0;
Lock lock =new ReentrantLock();
Condition condition=lock.newCondition();
public void increment() throws InterruptedException {
try {
lock.lock();
while (number !=0){
condition.await();
}
number++;
System.out.println(Thread.currentThread().getName() + "=>" + number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decrement() throws InterruptedException {
try {
lock.lock();
while (number ==0){
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName() + "=>" + number);
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
condition的精准实现
private Lock lock = new ReentrantLock();//新建锁
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
8锁的现象
1.多个线程使用同一把锁,顺序执行
package com.boom.example.demo.aa;
import java.util.concurrent.TimeUnit;
public class MultiThreadUseOneLock01 {
public static void main(String[] args) {
Mobile mobile = new Mobile();
new Thread(()->{
mobile.sendEmail();
}).start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
mobile.sendMS();
}).start();
}
}
class Mobile{
public synchronized void sendEmail(){
System.out.println("sendEmail");//先输出
}
public synchronized void sendMS(){
System.out.println("sendMS");
}
}
2.多个线程使用同一把锁,使其中某个线程阻塞,还是顺序执行
package com.boom.example.demo.aa;
import java.util.concurrent.TimeUnit;
public class MultiThreadUseOneLock01 {
public static void main(String[] args) {
Mobile mobile = new Mobile();
new Thread(()->{
mobile.sendEmail();
}).start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
mobile.sendMS();
}).start();
}
}
class Mobile{
public synchronized void sendEmail(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendEmail");//先执行
}
public synchronized void sendMS(){
System.out.println("sendMS");
}
}
3.多个线程有锁与没有锁,随机执行
两者不存在竞争同一把锁,执行顺序是随机的
package com.boom.example.demo.aa;
import java.util.concurrent.TimeUnit;
public class MultiThreadUseOneLock01 {
public static void main(String[] args) {
Mobile mobile = new Mobile();
new Thread(()->{
mobile.sendEmail();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
mobile.sendMS();
}).start();
new Thread(()->{
mobile.getWeixinMs();
}).start();
}
}
class Mobile{
public synchronized void sendEmail(){
System.out.println("sendEmail");
}
public synchronized void sendMS(){
System.out.println("sendMS");
}
public void getWeixinMs() {
System.out.println("getWeixinMs");
}
}
4.多个线程使用多把锁,随机执行
被synchronized修饰的方法,锁的对象是方法调用者
调用者不同,他们的锁不同,相互没有关系
package com.boom.example.demo.aa;
import java.util.concurrent.TimeUnit;
public class MultiThreadUseOneLock01 {
public static void main(String[] args) {
Mobile mobile1 = new Mobile();
Mobile mobile2 = new Mobile();
new Thread(()->{
mobile1.sendEmail();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
mobile2.sendMS();
}).start();
}
}
class Mobile{
public synchronized void sendEmail(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendEmail");
}
public synchronized void sendMS(){
System.out.println("sendMS");
}
}
5Class锁,多个线程使用一个对象,顺序执行
被synchronized和static同时修饰的方法锁的对象是类的class对象,线程顺序执行
锁class和锁对象的区别
class,类模板只有一个
对象锁,通过类模板可以new多个对象
如果是锁class,那new的对象都是同一把锁
package com.boom.example.demo.aa;
import java.util.concurrent.TimeUnit;
public class MultiThreadUseOneLock01 {
public static void main(String[] args) {
Mobile mobile = new Mobile();
new Thread(()->{
mobile.sendEmail();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
mobile.sendMS();
}).start();
}
}
class Mobile{
public synchronized static void sendEmail(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendEmail");
}
public synchronized static void sendMS(){
System.out.println("sendMS");
}
}
6多个线程使用多个对象,顺序执行
被 synchronized 修饰 和 static 修饰的方法,锁的对象是类的 class 对象,是唯一的一把锁。
Class锁是唯一的,所以多个对象使用的也是同一个Class锁
package com.boom.example.demo.aa;
import java.util.concurrent.TimeUnit;
public class MultiThreadUseOneLock01 {
public static void main(String[] args) {
Mobile mobile1 = new Mobile();
Mobile mobile2 = new Mobile();
new Thread(()->{
mobile1.sendEmail();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
mobile2.sendMS();
}).start();
}
}
class Mobile{
public synchronized static void sendEmail(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendEmail");
}
public synchronized static void sendMS(){
System.out.println("sendMS");
}
}
7class锁与对象锁,多个线程使用一个对象,随机执行
被 synchronized和static修饰的方法,锁的对象是类的class对象!唯一的同一把锁;
只被synchronized修饰的方法,是普通锁(如对象锁),不是Class锁,所以进程之间执行顺序互不干扰。
package com.boom.example.demo.aa;
import java.util.concurrent.TimeUnit;
public class MultiThreadUseOneLock01 {
public static void main(String[] args) {
Mobile mobile = new Mobile();
new Thread(()->{
mobile.sendEmail();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
mobile.sendMS();
}).start();
}
}
class Mobile{
public synchronized static void sendEmail(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendEmail");
}
public synchronized void sendMS(){
System.out.println("sendMS");
}
}
8 class锁与对象锁,多个线程使用多个对象,随机执行
package com.boom.example.demo.aa;
import java.util.concurrent.TimeUnit;
public class MultiThreadUseOneLock01 {
public static void main(String[] args) {
Mobile mobile1 = new Mobile();
Mobile mobile2 = new Mobile();
new Thread(()->{
mobile1.sendEmail();
}).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
mobile2.sendMS();
}).start();
}
}
class Mobile{
public synchronized static void sendEmail(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sendEmail");
}
public synchronized void sendMS(){
System.out.println("sendMS");
}
}