JUC(一)

线程

  • java并不能调用硬件开启线程,源码中private native void start0();使用native修饰是一个本地方法
  • java有两个线程mainGC
  • 线程的6个状态
public static enum State {
	// 新生	
    NEW,
    // 运行
    RUNNABLE,
    // 阻塞
    BLOCKED,
    // 等待
    WAITING,
    // 超时等待
    TIMED_WAITING,
    // 终止
    TERMINATED;

    private State() {
    }
}

wait和sleep区别

  • wait来自Object类,sleep来自Thread
  • wait会释放锁,sleep不会释放锁
  • wait需要在同步代码块中使用

synchronized和Lock区别

synchronizedLock
是JAVA关键字是一个类
可以自动释放锁需要手动解锁
不能判断锁的状态可以判断锁的状态
如果获取锁的线程阻塞,其它线程会一直等待如果获取锁的线程阻塞,可以尝试获取锁
可重入,不可中断,非公平可重入,可判断,(非)公平
适合少量代码适合大量代码

Synchronized锁:
调用锁的对象一样则调用的是同一把锁,对象不一样则调用的锁也不同
如果静态方法加锁,那么调用锁的就是该方法的模板,所以使用该类实例化出来的对象使用该静态方法调用的都是同一把锁

  • 普通同步方法,锁是当前实例对象
  • 静态同步方法,锁是当前类的class对象
  • 同步方法块,锁是括号里面的对象

Synchronized:synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性

生产者消费者问题

使用Synchronized

三步骤:判断是否等待,执行业务操作,通知。如:

// 生产者消费者问题
public class PCTest {
    public static void main(String[] args) {
        Data data = new Data();
        // 创建两个线程一个执行加一个执行减
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    data.increase();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    data.decrease();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "B").start();
    }
}

class Data {
    private int number = 0;

    // number +1
    public synchronized void increase() throws InterruptedException {
        // 如果不number不等0就等待其它线程完成减1操作
        if (number != 0) {
            this.wait();
        }
        // number等0就加1
        number++;
        System.out.println(Thread.currentThread().getName() + "->" + number);
        // 通知其它等待线程已完成操作
        this.notifyAll();
    }

    // number -1
    public synchronized void decrease() throws InterruptedException {
        if (number == 0) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "->" + number);
        this.notifyAll();
    }
}

输出的结果就是1,0交替出现
结果
如果在该例子的基础上再添加一个加一和减一两个线程则会出现,虚假唤醒的问题,结果如下:
结果
造成这种问题是因为我们使用了if只进行了一次判断,如果两个线程执行的都是加操作并且都进入了等待的状态,等到被唤醒时并不会再次判断而会直接执行下面的number++操作。所以解决的办法是将等待放进while循环之中

class Data {
    private int number = 0;

    public synchronized void increase() throws InterruptedException {
        // 使用while循环进行判断
        while (number != 0) {
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + "->" + number);
        this.notifyAll();
    }

    // number -1
    public synchronized void decrease() throws InterruptedException {
        while (number == 0) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + "->" + number);
        this.notifyAll();
    }
}

使用Lock

// 生产者消费者问题 Lock
public class PCTest1 {
    public static void main(String[] args) {
        Data1 data = new Data1();
        // 创建两个线程一个执行加一个执行减
        new Thread(() -> {
            for (int i = 0; i < 10; i++) data.increase();
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) data.decrease();
        }, "B").start();
    }
}

class Data1 {
    private int number = 0;
    // 获取可重入锁
    private Lock lock = new ReentrantLock();
    // 获取condition
    private Condition condition = lock.newCondition();

    public void increase() {
        // 加锁
        lock.lock();
        try {
            // 使用while循环进行判断
            while (number != 0) {
                //等待
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + "->" + number);
            // 唤醒
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 解锁
            lock.unlock();
        }
    }

    // number -1
    public synchronized void decrease() {
        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();
        }

    }
}

另外使用Lock中的Condition可以指定唤醒哪一个线程,如:

public class SpecifyWakeUp {
    public static void main(String[] args) {
        Say say = new Say();
        new Thread(()->{ for (int i = 0; i < 10; i++) say.printA(); }, "A").start();
        new Thread(()->{ for (int i = 0; i < 10; i++) say.printB(); }, "B").start();
        new Thread(()->{ for (int i = 0; i < 10; i++) say.printC(); }, "C").start();
    }

}

class Say{
    private int flag = 1;
    private Lock lock = new ReentrantLock();

    private Condition conditionA = lock.newCondition();
    private Condition conditionB = lock.newCondition();
    private Condition conditionC = lock.newCondition();

    // 这是A方法
    public void printA(){
        // 加锁
        lock.lock();
        try {
            while (flag != 1){
                // A线程等待
                conditionA.await();
            }
            flag = 2;
            System.out.println(Thread.currentThread().getName() + ":AAAAAA");
            // 唤醒B线程
            conditionB.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 解锁
            lock.unlock();
        }
    }
    // 这是B方法
    public void printB(){
        lock.lock();
        try {
            while (flag != 2){
                conditionB.await();
            }
            flag = 3;
            System.out.println(Thread.currentThread().getName() + ":BBBBBB");
            conditionC.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    // 这是C方法
    public void printC(){
        lock.lock();
        try {
            while (flag != 3){
                conditionC.await();
            }
            flag = 1;
            System.out.println(Thread.currentThread().getName() + ":CCCCCC");
            conditionA.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

读写锁

ReadWriteLock,用法与Lock相似
在这里插入图片描述

  • 读锁:允许多个线程进入
  • 写锁:只允许一个线程进入
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值