并发编程本质:充分利用CPU资源
并发:多线程操作同一资源(CPU单核,模拟出来多条线程,天下武功,唯快不破,快速交替)
并行:多个人一起行走 (CPU多核,多个线程可以同时执行,线程池)
public enum State {
// 新生
NEW,
// 运行
RUNNABLE,
// 阻塞
BLOCKED,
// 等待,死死地等
WAITING,
// 超时等待 (过时不等)
TIMED_WAITING,
// 终止
TERMINATED;
}
package com.kuang.demo01;
// 基本的卖票例子
/**
* 真正的多线程开发,公司中的开发
* 线程就是一个单独的资源类,没有任何附属的操作
*/
public class SaleTicketDemo01 {
public static void main(String[] args) {
// 并发 多线程操作同一个资源类
final Ticket ticket=new Ticket();
// 函数式接口
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"C").start();
}
}
// 资源类 OOP
class Ticket{
private int number=50;
// 卖票的方式
// synchronized 本质:队列,锁
public synchronized void sale(){
if (number>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"票,剩余:"+number);
}
}
}
// 资源类 OOP
// Lock三部曲
// 1、new ReentrantLock()
// 2、lock.lock() 加锁
// 3、lock.unlock() 解锁
class Ticket2{
private int number=30;
Lock lock=new ReentrantLock();//可重入锁
// 卖票的方式
public void sale(){
lock.lock();
try{
// 业务代码
if (number>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"票,剩余:"+number);
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
面试点:单例模式、排序算法、生产者和消费者、死锁
package com.kuang.pc;
// 线程之间的通信问题:生产者和消费者问题
// 线程交替执行 线程A B操作同一个变量
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;
public synchronized void increment() throws InterruptedException {
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();
}
}
注意点:当超过2个线程则判断等待时必须使用while,不能用if,因为会出现虚假唤醒情况(防止),即线程被唤醒,但不会通知、中断或者超时
package com.kuang.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();
public void increment() throws InterruptedException {
lock.lock();
try{
// 业务
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 {
lock.lock();
try{
// 业务
while (number==0){
condition.await();
}
number--;
System.out.println(Thread.currentThread().getName()+"=>"+number);
condition.signalAll();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
package com.kuang.pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
// 先执行线程A 再执行B 后执行C 一直保持这个顺序
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{
private Lock lock=new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
private int number=1;
public void printA(){
lock.lock();
try {
while (number!=1){
condition1.await();
}
number=2;
System.out.println(Thread.currentThread().getName()+"---->AAA");
condition2.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printB(){
lock.lock();
try {
while (number!=2){
condition2.await();
}
number=3;
System.out.println(Thread.currentThread().getName()+"---->BBB");
condition3.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void printC(){
lock.lock();
try {
while (number!=3){
condition3.await();
}
number=1;
System.out.println(Thread.currentThread().getName()+"---->CCC");
condition1.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
package com.kuang.lock8;
import java.util.concurrent.TimeUnit;
// 结果都是先发短信后打电话
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{phone.sendMsg();},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{phone.call();},"B").start();
}
}
class Phone{
// synchronized锁的对象是方法的调用者
// 两个方法使用的是同一把锁,谁先获取到谁先执行
public synchronized void sendMsg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
}
synchronized锁的对象是方法的调用者 两个方法使用的是同一把锁,谁先获取到谁先执行
package com.kuang.lock8;
import java.util.concurrent.TimeUnit;
// 3、增加了1个普通方法后,1s后先打印hello,等到了4s打印发短信
// 4、两个对象,两个同步方法,先打电话再发短信
public class Test2 {
public static void main(String[] args) {
Phone2 phone1 = new Phone2();
Phone2 phone2 = new Phone2();
new Thread(()->{phone1.sendMsg();},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
//new Thread(()->{phone.hello();},"B").start();
new Thread(()->{phone2.call();},"B").start();
}
}
class Phone2{
// synchronized锁的对象是方法的调用者
// 两个方法使用的是同一把锁,谁先获取到谁先执行
public synchronized void sendMsg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call(){
System.out.println("打电话");
}
//
public void hello(){
System.out.println("hello");
}
}
这里两个对象调用即有2把锁,这时根据等待时间长短决定谁先执行 结果即先打电话后发短信
package com.kuang.lock8;
import java.util.concurrent.TimeUnit;
// 5、增加2个静态的同步方法 一个对象调用
// 6、增加2个静态的同步方法 两个对象调用
// 结果:先发短信再打电话
public class Test3 {
public static void main(String[] args) {
// 两个对象都来自Class,记住锁的是Class(因为同步方法加了static)
Phone3 phone1 = new Phone3();
Phone3 phone2 = new Phone3();
new Thread(()->{phone1.sendMsg();},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{phone2.call();},"B").start();
}
}
class Phone3{
// 类一加载就有了,锁的是Class模板
public static synchronized void sendMsg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call(){
System.out.println("打电话");
}
}
加了static的同步方法,锁的是Class,所以不管是几个对象调用,谁先获取锁谁就先执行
package com.kuang.lock8;
import java.util.concurrent.TimeUnit;
// 7、1个静态同步方法 1个同步方法 1个对象
// 8、1个静态同步方法 1个同步方法 2个对象
public class Test4 {
public static void main(String[] args) {
// 两个对象都来自Class,记住锁的是Class(因为同步方法加了static)
Phone4 phone1 = new Phone4();
Phone4 phone2 = new Phone4();
new Thread(()->{phone1.sendMsg();},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{phone2.call();},"B").start();
}
}
class Phone4{
// 类一加载就有了,锁的是Class模板
public static synchronized void sendMsg(){
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
// synchronized锁的对象是方法的调用者
public synchronized void call(){
System.out.println("打电话");
}
}
先打电话再发短信因为静态同步方法锁的是Class,而普通同步方法锁的方法的调用者