JUC
java util concurrent
线程、进程
进程:一个程序。一个进程包含多个线程,至少包含一个。java默认有2个线程。main、GC
线程:开了一个进程mindManager,写字,线程负责自动保存
java真的可以开启线程吗
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
// 本地方法,底层是c++,java无法直接操作
private native void start0();
线程的状态:
public enum State {
// 新生
NEW,
// 运行
RUNNABLE,
// 阻塞
BLOCKED,
// 等待
WAITING,
// 超时等待
TIMED_WAITING,
// 终止
TERMINATED;
}
wait/sleep区别
- 来自不同类 Object-wait() Thread-sleep()
- 锁的是否释放 wait()释放锁 sleep()抱锁睡觉
- 使用范围不同 wait必须在同步代码块 sleep可以再任何地方睡
并发、并行
并发:多线程同时操作同一资源(充分利用CPU的资源)
CPU 一核,模拟多条线程
并行:多个人一起行走 CPU多核
Lock锁
线程就是一个单独的资源类,没有任何附属的操作
公平锁:可以先来后到
非公平锁:可以插队(默认非公平)
Lock锁可以在默认new ReetrantLock时构造函数方法参数中传true,使用公平锁,即使你执行的比我快,我也要遵循先来后到原则,决不允许你插队,这未遵循短作业优先原则,现实生活中,也同样如此。
synchronized和Lock锁的区别
- synchronized 内置的java关键字,Lock是一个java类
- synchronized无法判断锁的状态,Lock可以判断是否获取到了锁
- synchronized会自动释放锁,lock必须手动释放锁,否则死锁(手动挡赛车~)
- synchronized线程一(获得锁,阻塞)、线程二(等待,傻傻的等);Lock锁不一定会一直等待线程,lock.tryLock()
- synchronized可重入锁,不可以中断,非公平。lock可重入锁,可以判断锁,非公平
6.synchronized适合锁少量的代码同步问题,lock适合锁大量的同步代码
生产者消费者问题
/ 前后加 上锁lock 解锁unlock。
// 判断等待await,业务代码code,通知唤醒signal
synchronized版
传统synchronized版生产者消费者问题(if会引发虚假唤醒必须使用while):
突破!if/while使用问题,区别体现在juc并发编程中的生产者消费者问题中,如果用if只判断一次,而用while判断后会停下再次判断。
notify()和notifyAll()的区别,也体现在此处,二者兼顾一处就够(只有我懂),不要同时使用,用while就不要用notify(),二用notifyAll()。
/**
* 线程之间的通信问题:生产者消费之问题
* A num+1
* B num-1
* 要么用while不用if用notify()。要么用if不用while用notifyAll()
*/
public class Demo1 {
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();
}
}
},"Producter1").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Consumer1").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Producter2").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Consumer2").start();
}
}
// 前后加 上锁 解锁。
// 判断等待,业务代码,通知唤醒
class Data {
private int num = 0;
public synchronized void increment() throws InterruptedException {
while (num != 0) {
// num不为0,不能再加,须等待
// 等待
this.wait();
}
num++;
System.out.println(Thread.currentThread().getName()+"=>"+num);
// 通知其他线程,我+1完毕
this.notifyAll();
}
public synchronized void decrement() throws InterruptedException {
while (num == 0) {
// num为0,不能再减,须等待
// 等待
this.wait();
}
num--;
System.out.println(Thread.currentThread().getName()+"=>"+num);
// 通知其他线程,我-1完毕
this.notifyAll();
}
}
juc版
精准通知唤醒
精准通知去唤醒某个线程。通知线程一等待,通知线程二去唤醒线程一,线程一释放锁,线程二等待,通知线程三去唤醒线程二,线程二释放锁,通知线程三去唤醒线程一,线程三释放锁…
/**
* A执行完调用B b执行完执行c
*
* @Author Weton Li
* @Date 2021/2/8 14:47
*/
public class Demo3 {
public static void main(String[] args) {
Data3 data3 = new Data3();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data3.printA();
}
}, "a").start(); // a执行完通知b
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data3.printB();
}
}, "b").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
data3.printC();
}
}, "c").start();
}
}
class Data3 {
private Lock lock = new ReentrantLock();
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
private int num = 1; // 1a 2b 3c
/**
* 上锁->判断等待->业务代码->通知唤醒->解锁
*/
public void printA() {
lock.lock();
try {
while (num != 1) {
condition1.await();
}
System.out.println(Thread.currentThread().getName() + "=>aaa");
num = 2;
condition2.signal(); // 精准通知唤醒2
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
while (num != 2) {
condition2.await();
}
System.out.println(Thread.currentThread().getName() + "=>bbb");
num = 3;
condition3.signal(); // 精准通知唤醒3
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
while (num != 3) {
condition3.await();
}
System.out.println(Thread.currentThread().getName() + "=>ccc");
num = 1;
condition1.signal(); // 精准通知唤醒1
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
锁7原理
- 茵进厕所后安全上锁,直到茵上完厕所后,才轮到彤进厕所。
- 茵进厕所安全上锁,但由于彤非常不安全,彤用共用的一把钥匙开门而入去二坑位
- 茵进厕所安全上锁,新对象琦瞬间使用新钥匙开了另一扇新门
- 茵进厕所安全上锁,因彤安全,等待茵上完厕所后,才轮到彤上厕所
- 茵进厕所安全上锁,新对象琦即使有新钥匙也无法进入高级长方体厕所,只能等待茵上完厕所,琦在上厕所
扫描二维码关注公众号,回复:
13139151 查看本文章
- 此时琦忍无可忍,自己不再是全局静态static,只是某种意义上的synchronized,现在她破门而入,瞬间与茵一同上厕所。
public static synchronized void tjyWC() {
try {
TimeUnit.SECONDS.sleep(4); // 上4s厕所
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("茵上了4秒厕所");
}
// 这里不是static静态
public synchronized void hello() {
System.out.println("琦忍无可忍,去掉static,破门而入,与茵一同上厕所");
}
锁7详细代码
情形1
/**
* 锁的对象是方法的调用者
*
*/
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 (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
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");
}
}
情形2
/**
* 3.增加普通方法,先执行普通方法hello还是发短信? 普通方法hello
* 4.两个对象,发短信方法延迟四秒,都执行同步方法,先执行打电话还是发短信? 打电话
*/
public class Test2 {
public static void main(String[] args) {
// synchronized锁的对象是方法的调用者,拿到的锁不一样
Phone2 phone1 = new Phone2();
Phone2 phone2 = new Phone2();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
// phone2.call();
phone1.hello();
},"B").start();
}
}
class Phone2{
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");
}
}
情形3
/**
* 3.增加普通方法,先执行普通方法hello还是发短信? 普通方法hello
* 4.两个对象,发短信方法延迟四秒,都执行同步方法,先执行打电话还是发短信? 打电话
*/
public class Test2 {
public static void main(String[] args) {
// synchronized锁的对象是方法的调用者,拿到的锁不一样
Phone2 phone1 = new Phone2();
Phone2 phone2 = new Phone2();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
// phone1.hello();
},"B").start();
}
}
class Phone2{
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");
}
}
情形4
/**
* 4.两个静态同步方法,先发短信还是先打电话? 发短信
* 5.两个对象,两个静态同步方法,先发短信还是先打电话?发短信
*/
public class Test3 {
public static void main(String[] args) {
Phone3 phone1 = new Phone3();
Phone3 phone2 = new Phone3();
new Thread(() -> {
phone1.sendSms();
}, "a").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone1.call();
// phone2.call();
}, "b").start();
}
}
class Phone3 {
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");
}
}
情形5
/**
* 4.两个静态同步方法,先发短信还是先打电话? 发短信
* 5.两个对象,两个静态同步方法,先发短信还是先打电话?发短信
*/
public class Test3 {
public static void main(String[] args) {
Phone3 phone1 = new Phone3();
Phone3 phone2 = new Phone3();
new Thread(() -> {
phone1.sendSms();
}, "a").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
// phone1.call();
phone2.call();
}, "b").start();
}
}
class Phone3 {
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");
}
}
情形6
/**
* 6.一个静态同步方法,一个普通同步方法,一个对象,先普通同步方法还是发短信? 普通同步方法
* 7. 一个静态同步方法,一个普通同步方法,两个对象,先普通同步方法还是发短信? 普通同步方法
*/
public class Test4 {
public static void main(String[] args) {
Phone4 phone1 = new Phone4();
Phone4 phone2 = new Phone4();
new Thread(() -> {
phone1.sendSms();
}, "a").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone1.hello();
}, "b").start();
}
}
class Phone4 {
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");
}
// 这里不是static静态
public synchronized void hello() {
System.out.println("普通同步方法");
}
}
情形7
/**
* 6.一个静态同步方法,一个普通同步方法,一个对象,先普通同步方法还是发短信? 普通同步方法
* 7. 一个静态同步方法,一个普通同步方法,两个对象,先普通同步方法还是发短信? 普通同步方法
*/
public class Test4 {
public static void main(String[] args) {
Phone4 phone1 = new Phone4();
Phone4 phone2 = new Phone4();
new Thread(() -> {
phone1.sendSms();
}, "a").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
phone2.hello();
}, "b").start();
}
}
class Phone4 {
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");
}
// 这里不是static静态
public synchronized void hello() {
System.out.println("普通同步方法");
}
}