JUC相关随笔

一、基础

   JUC: java.util下面的concurrent以及concurrent.atomic、concurrent.locks并发包的总称

   线程:进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。

   进程:线程是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位。一个线程由一个或者多个线程组成,线程间共享进程的所有资源

   并发:是在同一个cpu上同时(不是真正的同时,而是看来是同时,因为cpu要在多个程序间切换)运行多个程序,即多个线程操作同一个资源,交替执行的过程

   并行:是每个cpu运行一个程序,即多个线程同时执行,只有在多核CPU下才能完成

  线程状态:新建(NEW)、运行(RUNNABLE)、阻塞(BLOCKED)、等待(WAITING)、延时等待(TIMED_WAITING)、终止(TERMINATED)

二、Wait/sleep区别(多线程编程中,线程休眠要用TimeUnit

   1 、类不同: wait是object类,sleep是 Thread

   2、会不会释放锁

       sleep:不会释放锁

      Wait:会释放锁

  3、使用的范围

     wait和notify是一组,一般在线程通信的时候使用

     sleep就是一个单独的方法,在任何地方都可以使用

  4、异常

    sleep需要捕获异常

    wait和notify则可以不捕获

三、synchronized和lock

synchronized实现:

package com.juc;

/**
* 传统的实现多线程方法:Synchronized
* Synchronized方法和Synchronized块
* 1、架构:高内聚,低耦合
* 2、线程操纵资源类,资源类是单独
*/
public class Demo1 {
public static void main(String[] args) {
//资源类
Ticket ticket = new Ticket();
new Ticket();
//线程操纵资源类
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
ticket.saleTicket();
}
}
}, "A").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
ticket.saleTicket();
}
}
}, "B").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 30; i++) {
ticket.saleTicket();
}
}
}, "c").start();

}
}

/**
* 资源类,只有属性和方法
* 这样草能实现复用
*/
class Ticket {

private int num = 30;

//同步锁,每次只能进来一个人,非公平锁
public synchronized void saleTicket() {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "卖出的第"+(num--) + "张票,还剩" + num+ "张票");
}
}
}

lock:

/**
* lock锁+lambda表达式
*/
public class Demo2 {
public static void main(String[] args) {
//1、创建资源类
Ticket2 ticket2=new Ticket2();
//2、线程操作资源类,所有函数式接口都可以用lambda表达式简化
new Thread(()->{for (int i = 0; i <30 ; i++)ticket2.saleTicket();},"A").start();
new Thread(()->{for (int i = 0; i <30 ; i++)ticket2.saleTicket();},"B").start();
new Thread(()->{for (int i = 0; i <30 ; i++)ticket2.saleTicket();},"C").start();
}
}

/**
* 资源类,只有属性和方法
* 这样草能实现复用
*/
class Ticket2 {

private int num = 30;
//1、使用lock,是一个对象
//2、ReentrantLock 可重入锁,回家:大门(卧室,书房)
//ReentrantLock默认是非公平的
//非公平锁:不公平(即可以插队,后面的线程可以插队)
//公平锁:公平(不能插队,只能排队,后面的线程无法插队)
private Lock lock = new ReentrantLock();
public void saleTicket() {
//加锁
lock.lock();
try {
//业务代码
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "卖出的第" + (num--) + "张票,还剩" + num + "张票");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//解锁
lock.unlock();
}

}
}

    区别:

     1、Synchronized是一个关键字,lock是一个类

     2、Synchronized无法尝试获取锁。lock可以尝试判断获取锁

    3、Synchronized会自动释放锁(a线程执行完毕,b线程异常了也会释放锁,)lock锁是可以手动释放锁,不释放就会死锁

    4、Synchronized(线程A获得锁,如果阻塞,B线程会一直等待)lock,可以尝试获取锁,失败之后就放弃

     5、Synchronized一定是非公平的,但是lock锁可以设置公平还是非公平,通过参数设置

     6、代码量大的时候,通过一般用Lock实现精准控制,Synchronized适合代码量比较少的同步问题

四:生产者和消费者

  1、synchronized

/**

* synchronized
* 目的:多个线程,还有一个变量nuber
* 多个个线程交替执行,对该变量+1-1
*/
public class Demo3 {
public static void main(String[] args) {

//新建资源类
Data data = new Data();
//()->{} lambda表达式
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.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 Data {
private int number = 0;

//number+1
public synchronized void increment() throws InterruptedException {
//判断
while (number != 0) {
this.wait();
}
//执行
number++;
System.out.println(Thread.currentThread().getName() + "\t" + number);
//通知
this.notifyAll();//唤醒所有线程
}

//number-1
public synchronized void decrement() throws InterruptedException {
//判断
while (number != 1) {
this.wait();
}
//执行
number--;
System.out.println(Thread.currentThread().getName() + "\t" + number);
//通知
this.notifyAll();//唤醒所有线程
}
}
2:lock
/**
* 实现线程之间的精准交替执行
*/
public class Demo4 {
public static void main(String[] args) {
//新建资源类
Data4 data4 = new Data4();
//线程操作资源类
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
data4.print5();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "A").start();
new Thread(() -> {
for (int i = 1; i <= 10; i++) {
try {
data4.print10();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "B").start();
new Thread(() -> {
try {
for (int i = 1; i <= 10; i++) {
data4.print15();
}
} catch (Exception e) {
e.printStackTrace();
}
}, "C").start();

}
}

class Data4 {
private int number = 1;
private Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();

public void print5() throws InterruptedException {
lock.lock();
try {
//判断
while (number != 1) {
condition1.await();
}
//执行
for (int i = 1; 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 = 1; i <= 15; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
//通知
number = 3;
condition3.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//解锁
lock.unlock();
}


}

public void print15() {
//加锁
lock.lock();
try {
//判断
while (number != 3) {
condition3.await();
}
//执行
for (int i = 1; i <= 15; i++) {
System.out.println(Thread.currentThread().getName() + "\t" + i);
}
//通知
number = 1;
condition1.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//解锁
lock.unlock();
}
}
}
    

猜你喜欢

转载自www.cnblogs.com/chenpeng199412/p/12411259.html
JUC
今日推荐