一、Java原生的并发包、常用的工具类
- java.util.concurrent 并发工具包
- java.util.concurrent.atomic 原子包
- java.util.concurrent.locks 锁
- java.util.function 函数
二、什么是线程和进程?
进程: wexi.exe
线程: 打字、自动保存。。。
一个进程可以包含多个线程,一个进程至少有两个线程!java程序至少两个线程:GC、 Main
并发、并行
并发:多个线程操作同一个资源、交替执行的过程!
并行:多个线程同时执行!只有在多核CPU下才能完成!
所有我们使用多个线程或者并发编程目的:提高效率,让CPU一直工作,达到最高处理性能!
三、线程有几种状态
线程有六状态,学会面向源码学习
public enum State {
//java能够创建线程?
NEW
//运行
RUNNABLE,
//阻塞
BLOCKED,
//等待
WAITING,
//延时等待
TIMED_WAITING,
//终止
TERMINATED;
}
四、Wait/Sleep区别
1、类不同!
wait: Object 类 Sleep Thread
在juc编程中,线程休眠怎么实现!Thread.Sleep
//时间单位
TimeUnit.SECONDS.sleep(3);
2、会不会释放资源
Sleep:抱着锁睡着、不会释放锁!wait会释放锁
3、使用的范围是不同
Wait和notify是一组,一般在线程通信的时候使用!
Sleep 就是一个单独的方法、在哪里都可以用!
4、关于异常
Sleep需要捕获异常!
五、Lock锁
Synchronized 传统的使用
package com.coding.demo01;
import java.util.concurrent.TimeUnit;
//传统的 Synchronized
//Synchronized 方法 和 Synchronized 类
/**
- 1、架构思想: 高内聚 、底耦合
- 2、并发编程思想:线程操作资源类、资源类是单独类
*/
public class Demo01 {
public static void main(String[] args) {
// new Thread(new Ticket()).start();
//1、新建资源类
final Ticket1 ticket = new Ticket1();
//2、线程操作资源类
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 40; i++) {
ticket.saleTicket();
}
}
},"A").start();
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 40; i++) {
ticket.saleTicket();
}
}
},"B").start();
new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 40; i++) {
ticket.saleTicket();
}
}
},"C").start();
}
}
//class Ticket implements Runnable {
//
// public void run() {
//
// }
//}
//单独的资源类,属性和方法
class Ticket1 {
private int number =30;
//同步锁,测试=》close
//synchronized 是一个关键字
public synchronized void saleTicket(){
if(number>0){
System.out.println(Thread.currentThread().getName()+"卖出第"+(number--)+"票,还剩:"+number);
}}}
Lock锁
package com.coding.demo01;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* -- Created by IntelliJ IDEA.
* -- REMARK:
* -- User: tanwei
* -- Date: 2020/6/18
* -- Time: 10:32 上午
* --
* JUC 之后操作
* lock锁 +lambda 表达式
*/
public class Dome02 {
public static void main(String[] args) {
//1.新建资源类
Ticket02 ticket02 = new Ticket02();
//2.线程操作资源类,所有的函数接口都可以用lambda表示简化!
//()->{}lambda表达式(参数) ->{具体代码}
new Thread(()->{ for (int i = 0; i <40; i++) {ticket02.saleTicket(); } },"A").start();
new Thread(()->{ for (int i = 0; i <40; i++) {ticket02.saleTicket(); } },"B").start();
new Thread(()->{ for (int i = 0; i <40; i++) {ticket02.saleTicket(); } },"C").start();
}
}
//依旧是一个资源类
class Ticket02 {
//使用lock,它是一个对象
//ReentrantLock 可重入锁: 回家:大门(卧室,厨房。。。)
//ReentrantLock 默认是非公平锁!
//非公平是: 不公平 (插队,后面线程可以插队)
//公平是: 公平 (只能排到,后面线程不可以插队)
private Lock lock = new ReentrantLock();
private int number = 30;
public synchronized void saleTicket() {
lock.lock();//加锁
try {
if (number > 0) {
System.out.println(Thread.currentThread().getName() + "卖出第" + (number--) + "票,还剩:" + number);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();//解算
}
}
}
六、Synchronized 和lock区别
1、Synchronized 是一个关键字、lock是一个对象
2、Synchronized 无法长沙获取锁,lock 可以尝试获取锁、判断;
3、Synchronized会自动释放锁(a线程执行完比b如果异常了,也会释放锁),lock锁是手动释放锁!如果你不释放就会死锁
4、Synchronized(线程A(获得锁,如果阻塞),线程B(等待);)lock 可以尝试获取锁、失败了之后就放弃
5、Synchronized 一定是非公平的,但是Lock 锁可以试公平的、可以通过参数设置;
6、代码量特别大的时候,我们一棒使用lock实现精准控制、Synchronized 适合代码量比较小的同步问题;
七、生产者消费者问题
单例模式 排序算法 死锁、生成者消费者
线程和线程之间本来不能通信的、但是有时候我们需要线程之间协调操作:
Synchronized:普通版
package com.coding.demo01;
/**
* -- Created by IntelliJ IDEA.
* -- REMARK:
* -- User: tanwei
* -- Date: 2020/6/18
* -- Time: 10:34 上午
* --
*
*
* Synchronized 版
* 目的: 有两个线程:A B,还有一个值初始为0,
* 实现两个线程交替执行,对该变量 +1,-1;交替10次
*/
public class Demo03 {
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()+"\t"+number);
//通知
this.notifyAll();//唤醒所有线程
}
//-1
public synchronized void decrement() throws InterruptedException {
if(number==0){//判断是否需要等待
this.wait();
}
number--;//执行
System.out.println(Thread.currentThread().getName()+"\t"+number);
//通知
this.notifyAll();//唤醒所有线程
}}
传统的唤醒
package com.coding.demo01;
/**
* -- Created by IntelliJ IDEA.
* -- REMARK:
* -- User: tanwei
* -- Date: 2020/6/18
* -- Time: 10:34 上午
* --
* Synchronized 版
* 目的: 有两个线程:A B,还有一个值初始为0,
* 实现两个线程交替执行,对该变量 +1,-1;交替10次
*
* 传统的wait 和notifyAll 不能精准唤醒
*/
public class Demo04 {
public static void main(String[] args) {
Data4 data = new Data4();
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.increment();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
} 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 Data4 {
private int number = 0;
//+1
public synchronized void increment() throws InterruptedException {
while (number!=0){//判断是否需要等待
this.wait();
}
number++;//执行
System.out.println(Thread.currentThread().getName()+"\t"+number);
//通知
this.notifyAll();//唤醒所有线程
}
//-1
public synchronized void decrement() throws InterruptedException {
while (number==0){//判断是否需要等待
this.wait();
}
number--;//执行
System.out.println(Thread.currentThread().getName()+"\t"+number);
//通知
this.notifyAll();//唤醒所有线程
}}
package com.coding.demo01;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* -- Created by IntelliJ IDEA.
* -- REMARK:
* -- User: tanwei
* -- Date: 2020/6/18
* -- Time: 1:11 下午
* --
* 实现线程交换执行
* 主要的实现目标,;精准的唤醒线程!
* <p>
* 三个线程:A B C
* 三个方法:A p5 B p10 C p15 依次循环
*/
public class Demo05 {
public static void main(String[] args) {
Data3 data = new Data3();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.print5();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.print10();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
data.print15();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "C").start();
}
}
class Data3 {
private int number = 1;//1A 2B 3C
private Lock lock = new ReentrantLock();
//实现精准访问
private Condition condition1 = lock.newCondition();
private Condition condition2 = lock.newCondition();
private Condition condition3 = lock.newCondition();
public void print5() throws InterruptedException {
lock.lock();
//判断
try {
while (number != 1) {
condition1.await();
}
//执行
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
//通知第二个线程干活
number = 2;
condition2.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void print10() throws InterruptedException {
lock.lock();
//判断
try {
while (number != 2) {
condition2.await();
}
//执行
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
//通知
number = 3;
condition3.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void print15() throws InterruptedException {
lock.lock();
//判断
try {
while (number != 3) {
condition3.await();
}
//执行
for (int i = 0; i < 15; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
//通知
number = 1;
condition1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
新的技术、一定是可以替换一些旧技术!
八、八锁现象线程彻底解锁
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
/**
* -- Created by IntelliJ IDEA.
* -- REMARK: lock
* -- User: tanwei
* -- Date: 2020/6/19
* -- Time: 2:34 下午
* --
* 标准的访问情况下,先执行 sendEmail 还是 sendSMS
*
* 被 synchronized 修饰的方式,锁的对象是方法的调用者,所有说这两个方法调用的对象是同一个先调用先执行
*/
public class Lock01 {
public static void main(String[] args) throws InterruptedException {
Phone phone = new Phone();
new Thread(() -> {
phone.sendEmail();
},"A").start();
TimeUnit.SECONDS.sleep(2);
new Thread(() -> {
phone.sendSMS();
},"B").start();
}
}
class Phone {
public synchronized void sendEmail() {
System.out.println("sendEmail");
}
public synchronized void sendSMS() {
System.out.println("sendSMS");
}
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
/**
* -- Created by IntelliJ IDEA.
* -- REMARK: lock
* -- User: tanwei
* -- Date: 2020/6/19
* -- Time: 2:34 下午
* --
*
* sendEmail暂停三秒,先执行 sendEmail 还是 sendSMS
*
* 被 synchronized 修饰的方式,锁的对象是方法的调用者,所有说这两个方法调用的对象是同一个先调用先执行
*/
public class Lock02 {
public static void main(String[] args) throws InterruptedException {
Phone02 phone = new Phone02();
new Thread(() -> {
try {
phone.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"A").start();
TimeUnit.SECONDS.sleep(2);
new Thread(() -> {
phone.sendSMS();
},"B").start();
}
}
class Phone02 {
public synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}
public synchronized void sendSMS() {
System.out.println("sendSMS");
}
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
/**
* -- Created by IntelliJ IDEA.
* -- REMARK: lock
* -- User: tanwei
* -- Date: 2020/6/19
* -- Time: 2:34 下午
* --
* <p>
* 增加一个普通方法,先执行 sendEmail 还是 sendSMS
* <p>
*
* 新增加的这个方法没有synchronized 修饰 不是同步方法、不受影响
*/
public class Lock03 {
public static void main(String[] args) throws InterruptedException {
Phone03 phone = new Phone03();
new Thread(() -> {
try {
phone.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {
phone.sendSMS();
}, "B").start();
}
}
class Phone03 {
public synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}
public void sendSMS() {
System.out.println("sendSMS");
}
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
/**
* -- Created by IntelliJ IDEA.
* -- REMARK: lock
* -- User: tanwei
* -- Date: 2020/6/19
* -- Time: 2:34 下午
* --
* <p>
* 两个手机 请问先执行sendemail 还是 sendSMS
* <p>
*
* 被synchronized 修饰的方式 ,锁的对象是方法的调用者,所以说这里两个方法调用的对象是同一个对象先调用先执行
*/
public class Lock04 {
public static void main(String[] args) throws InterruptedException {
Phone04 phone = new Phone04();
Phone04 phone1 = new Phone04();
new Thread(() -> {
try {
phone.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {
phone1.sendSMS();
}, "B").start();
}
}
class Phone04 {
public synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}
public synchronized void sendSMS() {
System.out.println("sendSMS");
}
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
/**
* -- Created by IntelliJ IDEA.
* -- REMARK: lock
* -- User: tanwei
* -- Date: 2020/6/19
* -- Time: 2:34 下午
* --
* <p>
* Lock05.class 模板,只有一个static
* new Lock05(), 可以创建多个对象
* 两个静态方法 请问先执行sendemail 还是 sendSMS
* <p>
*
* 只要方法被static 修饰 、锁的对象就是class模板对象,这个则是全局唯一!所以说这里是同一个对象
*/
public class Lock05 {
public static void main(String[] args) throws InterruptedException {
Phone05 phone = new Phone05();
new Thread(() -> {
try {
phone.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {
phone.sendSMS();
}, "B").start();
}
}
class Phone05 {
public static synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}
public static synchronized void sendSMS() {
System.out.println("sendSMS");
}
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
/**
* -- Created by IntelliJ IDEA.
* -- REMARK: lock
* -- User: tanwei
* -- Date: 2020/6/19
* -- Time: 2:34 下午
* --
* <p>
* Lock05.class 模板,只有一个static
* new Lock05(), 可以创建多个对象
* 两个静态方法 请问先执行sendemail 还是 sendSMS
* <p>
*
* 只要方法被static 修饰 、锁的对象就是class模板对象,这个则是全局唯一!所以说这里是同一个对象
*/
public class Lock06 {
public static void main(String[] args) throws InterruptedException {
Phone06 phone = new Phone06();
Phone06 phone1 = new Phone06();
new Thread(() -> {
try {
phone.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {
phone1.sendSMS();
}, "B").start();
}
}
class Phone06 {
public static synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}
public static synchronized void sendSMS() {
System.out.println("sendSMS");
}
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
/**
* -- Created by IntelliJ IDEA.
* -- REMARK: lock
* -- User: tanwei
* -- Date: 2020/6/19
* -- Time: 2:34 下午
* --
* <p>
* Lock05.class 模板,只有一个static
* new Lock05(), 可以创建多个对象
*
* <p>
*
* synchronized 锁的是这个调用对象
* static 锁的是这个类的class 模板
*
* 这里是两个锁
*
*/
public class Lock07 {
public static void main(String[] args) throws InterruptedException {
Phone07 phone = new Phone07();
new Thread(() -> {
try {
phone.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {
phone.sendSMS();
}, "B").start();
}
}
class Phone07 {
public static synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}
public synchronized void sendSMS() {
System.out.println("sendSMS");
}
}
package com.coding.lock8;
import java.util.concurrent.TimeUnit;
/**
* -- Created by IntelliJ IDEA.
* -- REMARK: lock
* -- User: tanwei
* -- Date: 2020/6/19
* -- Time: 2:34 下午
* --
* <p>
* Lock05.class 模板,只有一个static
* new Lock05(), 可以创建多个对象
*
* <p>
* <p>
* synchronized 锁的是这个调用对象
* static 锁的是这个类的class 模板
* <p>
* 这里是两个锁
*/
public class Lock08 {
public static void main(String[] args) throws InterruptedException {
Phone08 phone = new Phone08();
Phone08 phone1 = new Phone08();
new Thread(() -> {
try {
phone.sendEmail();
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "A").start();
TimeUnit.SECONDS.sleep(1);
new Thread(() -> {
phone1.sendSMS();
}, "B").start();
}
}
class Phone08 {
public static synchronized void sendEmail() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("sendEmail");
}
public synchronized void sendSMS() {
System.out.println("sendSMS");
}
}
总结:
1 、new this 调用的这个对象,是一个具体的对象
2、static class 唯一的一个模板!
在编写多线程的时候,只需要搞明白这个到底锁的是什么就不出错了