什么是JUC
juc 就是java.util,concurrent 工具包的简称,这是一个处理线程的工具包。
什么是线程和进程
线程:线程作为资源调度的基本单位,是程序的执行单位,执行路径(单线程:一条执行路径,多线程:多条执行路径)是程序使用Cpu 的最基本的单位。
进程:进程就是程序的一次执行,进程是一个程序及其数据在处理机上顺序执行时所发生的活动。它是系统进行资源丰沛和调度的单位。
在电脑的cpu 使用情况看,一个进程可能会有多个线程。至少也是一个!。
Java 真的可以开启线程吗?
不可以,看源码。


java中被native 所修饰的,都是本地的方法,是底层C++所写的。我们没有办法通过Java 获取到。
并行和并发
并行:同一时间段,多个线程操作同一个资源。
并发:单位时间内,多个人一起。
线程的几种状态
是个枚举类
public enum State {
//创建状态
NEW,
//运行时状态
RUNNABLE,
//锁状态
BLOCKED,
//等待状态
WAITING,
//超时等待
TIMED_WAITING,
//终止状态
TERMINATED;
}
sleep 和wait 的区别?
1,来自不同的类
wait ⇒ Object
sleep=> Thread
2,关于锁的释放
wait 会释放锁,sleep 睡觉了,抱着锁睡觉,不会睡觉!
3,使用的范围时不同的
wait :必须在同步代码块中
sleep 可以在任何地方睡。
传统的synchronized 锁
案例demo 我们来模拟一下卖票的案例,在我们不加锁的情况下会出现冲突
package com.jj.demo;
/**
* @author fjj
* @date 2021/3/18 18:53
*/
public class Demo {
public static void main(String[] args) {
//开启多线程卖票
tickets tickets = new tickets();
//使用lambda 表达式
new Thread(()->{
for (int i = 1; i < 50; i++) {
tickets.save();
}
},"A").start();
new Thread(()->{
for (int i = 1; i < 50; i++) {
tickets.save();
}
},"B").start();
}
}
class tickets{
//定义我们一共有多少张票
private int number =40;
//卖票的方法
public void save(){
if (number>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"还有"+number +"张票");
}
}
}
结果
错的一塌糊涂。
我们可以加一个关键字synchronized
结果
不会出现错的情况,这是加最简单的一种锁的方式。
但是我们比没有用到我们的JUC 所以我们需要使用Juc 有关的。
LOCK 锁的使用
JDK 1.8 的api 文档
Lock 的三个实现类

公平锁: 十分公平;可以先来后到
非公平锁:十分不公平:可以插队(默认)
还是原来的代码 只是用了lock 锁
package com.jj.demo;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author fjj
* @date 2021/3/19 18:52
*/
public class Demo1 {
public static void main(String[] args) {
//开启多线程卖票
tickets1 tickets = new tickets1();
//使用lambda 表达式
new Thread(()->{ for (int i = 1; i < 50; i++) tickets.save(); },"A").start();
new Thread(()->{ for (int i = 1; i < 50; i++) tickets.save(); },"B").start();
}
}
class tickets1{
//定义我们一共有多少张票
private int number =40;
//实现LOCK
Lock lock= new ReentrantLock();
//卖票的方法
public void save(){
//加锁
lock.lock();
try {
//业务代码
if (number>0){
System.out.println(Thread.currentThread().getName()+"卖出了第"+(number--)+"还有"+number +"张票");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
lock 锁使用的三个步骤
1,使用实现类//
2,lock .lock() //加锁
3,在finally 块里解锁 //
两个都可以实现,但是 lock 和synchronized 还是有区别的?
1,synchronized 内置的Java 关键字,Lock 是一个Java 类
2,synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁
3,synchronized 会自动释放锁,Lock 必须要手动释放锁!如果不释放锁,死锁
4,synchronized 线程1(获取锁,阻塞),线程2 (等待,傻傻的等)Lock 锁就不会等下去
5,synchronized 可重入锁,不可以中断的,非公平;Lock 可重入锁,可以判断锁,非公平(可以自己设置)
6,synchronized 适合少量的代码同步问题,Lock 适合锁大量的同步代码。
synchronized 版的生产者和消费者测试
package com.jj.demo.Producer;
/**
* @author fjj
* @date 2021/3/19 20:12
*/
public class Demo1 {
public static void main(String[] args) {
A a = new A();
//开启线程
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
a.incr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
a.decr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"B").start();
}
}
class A{
//定义一个数字
private int number =0;
//+1 的操作
public synchronized void incr() throws Exception {
if (number!=0){
//如果不等于0 就让线程等待
this.wait();
}
number++;
System.out.println("是"+Thread.currentThread().getName()+"在加数据"+number);
//通知其他的线程 我加1 完毕
this.notifyAll();
}
//同理 -1 的操作
public synchronized void decr() throws Exception {
if (number==0){
//如果不等于0 就让线程等待
this.wait();
}
number--;
System.out.println("是"+Thread.currentThread().getName()+"在加数据"+number);
//通知其他的线程 我加1 完毕
this.notifyAll();
}
}
结果
这样看没有错误,但是 如果是在来几个线程的话,就会出现问题
package com.jj.demo.Producer;
/**
* @author fjj
* @date 2021/3/19 20:12
*/
public class Demo1 {
public static void main(String[] args) {
A a = new A();
//开启线程
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
a.incr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
a.decr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
a.incr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
a.decr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"D").start();
}
}
class A{
//定义一个数字
private int number =0;
//+1 的操作
public synchronized void incr() throws Exception {
if (number!=0){
//如果不等于0 就让线程等待
this.wait();
}
number++;
System.out.println("是"+Thread.currentThread().getName()+"在加数据"+number);
//通知其他的线程 我加1 完毕
this.notifyAll();
}
//同理 -1 的操作
public synchronized void decr() throws Exception {
if (number==0){
//如果不等于0 就让线程等待
this.wait();
}
number--;
System.out.println("是"+Thread.currentThread().getName()+"在加数据"+number);
//通知其他的线程 我加1 完毕
this.notifyAll();
}
}
我又加了2条线程就出现了错误
这是因为我们在用if 判断的时候出现了虚假判断,按照官方文档我们需要更改一下判断的条件,不可以用if 判断,我们应该用的是while
package com.jj.demo.Producer;
/**
* @author fjj
* @date 2021/3/19 20:12
*/
public class Demo1 {
public static void main(String[] args) {
A a = new A();
//开启线程
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
a.incr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
a.decr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
a.incr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
a.decr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"D").start();
}
}
class A{
//定义一个数字
private int number =0;
//+1 的操作
public synchronized void incr() throws Exception {
while (number!=0){
//如果不等于0 就让线程等待
this.wait();
}
number++;
System.out.println("是"+Thread.currentThread().getName()+"在加数据"+number);
//通知其他的线程 我加1 完毕
this.notifyAll();
}
//同理 -1 的操作
public synchronized void decr() throws Exception {
while (number==0){
//如果不等于0 就让线程等待
this.wait();
}
number--;
System.out.println("是"+Thread.currentThread().getName()+"在加数据"+number);
//通知其他的线程 我加1 完毕
this.notifyAll();
}
}
改为while 判断的时候就好了
Lock 锁的生产者消费者的案例
package com.jj.demo.Producer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author fjj
* @date 2021/3/19 20:53
*/
public class Demo2 {
public static void main(String[] args) {
B b = new B();
//开启线程
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
b.incr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
b.decr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
b.incr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i <10 ; i++) {
try {
b.decr();
} catch (Exception e) {
e.printStackTrace();
}
}
},"D").start();
}
}
class B{
//定义一个数字
private int number =0;
//获取Lock
Lock lock =new ReentrantLock();
Condition condition = lock.newCondition();
//+1 的操作
public void incr() throws Exception {
lock.lock();
try {
while (number!=0){
//如果不等于0 就让线程等待
condition.await();
}
number++;
System.out.println("是"+Thread.currentThread().getName()+"在加数据"+number);
//通知其他的线程 我加1 完毕
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
//同理 -1 的操作
public void decr() throws Exception {
lock.lock();
try {
while (number==0){
//如果不等于0 就让线程等待
condition.await();
}
number--;
System.out.println("是"+Thread.currentThread().getName()+"在加数据"+number);
//通知其他的线程 我加1 完毕
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
实现的类不同还有方法也不同了,不过结果
不是有序排列的。
设置指定唤醒的锁
package com.jj.demo.Producer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author fjj
* @date 2021/3/20 14:26
*/
public class Demo3 {
public static void main(String[] args) {
//获取对象
C c = new C();
//创建线程
new Thread(()->{
for (int i = 0; i < 10; i++) {
c.printA();
}
},"A").start();
//创建线程
new Thread(()->{
for (int i = 0; i < 10; i++) {
c.printB();
}
},"B").start();
}
}
//需求 当A=1 时线程A执行,否侧是B
class C{
//定义一个数字用来判断
private int number =1;
private Lock lock=new ReentrantLock();
Condition condition = lock.newCondition();
Condition condition1 = lock.newCondition();
public void printA(){
//开启锁
lock.lock();
try {
//业务代码
while (number!=1){
//等待
condition.await();
}
System.out.println(Thread.currentThread().getName()+"A");
//唤醒指定的锁
condition1.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
//解锁
lock.unlock();
}
}
public void printB(){
//开启锁
lock.lock();
try {
//业务代码
while (number<1){
//等待
condition1.await();
}
System.out.println(Thread.currentThread().getName()+"B");
//唤醒指定的锁
condition.signal();
} catch (Exception e) {
e.printStackTrace();
} finally {
//解锁
lock.unlock();
}
}
}
锁的8个问题
这是一个正常得加锁得案例
package com.jj.demo;
/**
* @author fjj
* @date 2021/3/20 14:48
*/
public class Lock8 {
public static void main(String[] args) {
// 获取对象得实例
phone phone = new phone();
//创建线程A,B
new Thread(()->{
phone.send();
},"A").start();
new Thread(()->{
phone.call();
},"B").start();
}
}
//电话类
class phone{
//发短信得方法
public synchronized void send(){
System.out.println("我是发短信得功能");
}
//打电话得功能
public synchronized void call(){
System.out.println("我是打电话功能");
}
}
结果
问题一。现在有一个电话类,两个方法。一个发短信,一个打电话方法。假设现在让 线程A睡眠 1 s 是先执行发短信还是先执行 打电话方法?
package com.jj.demo;
import java.util.concurrent.TimeUnit;
/**
* @author fjj
* @date 2021/3/20 14:48
*/
public class Lock8 {
public static void main(String[] args) throws Exception {
// 获取对象得实例
phone phone = new phone();
//创建线程A,B
new Thread(()->{ phone.send(); },"A").start();
//线程睡眠
TimeUnit.SECONDS.sleep(1);
new Thread(()->{ phone.call(); },"B").start();
}
}
//电话类
class phone{
//发短信得方法
public synchronized void send(){
System.out.println("我是发短信得功能");
}
//打电话得功能
public synchronized void call(){
System.out.println("我是打电话功能");
}
}
结果
问题二,让在方法里让发短信得方法睡觉 4S 结果会是什么?
package com.jj.demo;
import java.util.concurrent.TimeUnit;
/**
* @author fjj
* @date 2021/3/20 14:48
*/
public class Lock8 {
public static void main(String[] args) throws InterruptedException {
// 获取对象得实例
phone phone = new phone();
//创建线程A,B
new Thread(()->{
try {
phone.send();
} catch (Exception e) {
e.printStackTrace();
}
},"A").start();
//线程睡眠
TimeUnit.SECONDS.sleep(1);
new Thread(()->{ phone.call(); },"B").start();
}
}
//电话类
class phone{
//发短信得方法
public synchronized void send() throws Exception {
System.out.println("我是发短信得功能");
//线程睡眠
TimeUnit.SECONDS.sleep(4);
}
//打电话得功能
public synchronized void call(){
System.out.println("我是打电话功能");
}
}
结果
synchronized 锁得是调用得同一个调用得调用者。原因是因为线程A先拿到了锁。就算睡眠也是抱着锁睡觉得。因为是它先拿到得锁
问题三,当我们在phone 里加了一个没有加锁得方法。此时先执行得就不是发短信 ps(估计我的cpu 太快了,我的居然还是发短信。。。)
package com.jj.demo;
import java.util.concurrent.TimeUnit;
/**
* @author fjj
* @date 2021/3/20 14:48
*/
public class Lock8 {
public static void main(String[] args) throws InterruptedException {
// 获取对象得实例
phone phone = new phone();
//创建线程A,B
new Thread(()->{
try {
phone.send();
} catch (Exception e) {
e.printStackTrace();
}
},"A").start();
//线程睡眠
TimeUnit.SECONDS.sleep(1);
new Thread(()->{phone.hello();},"B").start();
}
}
//电话类
class phone{
//发短信得方法
public synchronized void send() throws Exception {
System.out.println("我是发短信得功能");
//线程睡眠
TimeUnit.SECONDS.sleep(4);
}
//你好得方法
public void hello(){
System.out.println("我是没有加锁的你好方法");
}
}
问题四,现在有两个对象,一个对象调用 send 方法,一个调用打电话,同理 还是休息4秒
package com.jj.demo;
import java.util.concurrent.TimeUnit;
/**
* @author fjj
* @date 2021/3/20 14:48
*/
public class Lock8 {
public static void main(String[] args) throws InterruptedException {
// 获取对象得实例
phone phone = new phone();
phone phone1 = new phone();
//创建线程A,B
new Thread(()->{
try {
phone.send();
} catch (Exception e) {
e.printStackTrace();
}
},"A").start();
//线程睡眠
TimeUnit.SECONDS.sleep(1);
new Thread(()->{phone1.call();},"B").start();
}
}
//电话类
class phone{
//发短信得方法
public synchronized void send() throws Exception {
System.out.println("我是发短信得功能");
//线程睡眠
TimeUnit.SECONDS.sleep(100);
}
//打电话
public synchronized void call(){
System.out.println("打电话");
}
}
我的结果居然还是发短信,我哭了。道理应该是不同得对象,发短信线程还在睡觉应该是打电话先走。但是我的电脑就不让打电话得方法拿到锁。哭了。。。。。。。
问题五,六 。当两个方法都被static 给修饰后,相当于锁得是类了。所以无论与对象调用已经无关了,锁得是phone 类了。
package com.jj.demo;
import java.util.concurrent.TimeUnit;
/**
* @author fjj
* @date 2021/3/20 14:48
*/
public class Lock8 {
public static void main(String[] args) throws InterruptedException {
// 获取对象得实例
phone phone = new phone();
phone phone1 = new phone();
//创建线程A,B
new Thread(()->{
try {
phone.send();
} catch (Exception e) {
e.printStackTrace();
}
},"A").start();
//线程睡眠
TimeUnit.SECONDS.sleep(1);
new Thread(()->{phone1.call();},"B").start();
}
}
//电话类
class phone{
//发短信得方法
public static synchronized void send() throws Exception {
System.out.println("我是发短信得功能");
//线程睡眠
TimeUnit.SECONDS.sleep(4);
}
//打电话
public static synchronized void call(){
System.out.println("打电话");
}
}
问题七,当一个方法是static 一个方法没有被static 所修饰得时候。这个时候就是打电话得方法先出来, 因为不是同一把锁了
package com.jj.demo;
import java.util.concurrent.TimeUnit;
/**
* @author fjj
* @date 2021/3/20 14:48
*/
public class Lock8 {
public static void main(String[] args) throws InterruptedException {
// 获取对象得实例
phone phone = new phone();
//创建线程A,B
new Thread(()->{
try {
phone.send();
} catch (Exception e) {
e.printStackTrace();
}
},"A").start();
//线程睡眠
TimeUnit.SECONDS.sleep(1);
new Thread(()->{phone.call();},"B").start();
}
}
//电话类
class phone{
//发短信得方法
public static synchronized void send() throws Exception {
System.out.println("我是发短信得功能");
//线程睡眠
TimeUnit.SECONDS.sleep(4);
}
//打电话
public synchronized void call(){
System.out.println("打电话");
}
}
问题八,当我们有两个对象得时候,还是一个是static 修饰,一个是 普通得锁
package com.jj.demo;
import java.util.concurrent.TimeUnit;
/**
* @author fjj
* @date 2021/3/20 14:48
*/
public class Lock8 {
public static void main(String[] args) throws InterruptedException {
// 获取对象得实例
phone phone = new phone();
phone phone1 = new phone();
//创建线程A,B
new Thread(()->{
try {
phone.send();
} catch (Exception e) {
e.printStackTrace();
}
},"A").start();
//线程睡眠
TimeUnit.SECONDS.sleep(1);
new Thread(()->{phone1.call();},"B").start();
}
}
//电话类
class phone{
//发短信得方法
public static synchronized void send() throws Exception {
System.out.println("我是发短信得功能");
//线程睡眠
TimeUnit.SECONDS.sleep(4);
}
//打电话
public synchronized void call(){
System.out.println("打电话");
}
}
集合不安全类
并发情况下得Arrlist 安全吗?案例
package com.jj.demo.listdemo;
import java.util.ArrayList;
import java.util.UUID;
/**
* @author fjj
* @date 2021/3/20 15:51
*/
public class ListDemo {
public static void main(String[] args) {
//创建集合类
ArrayList<String> list = new ArrayList<>();
//循环放入数据
for (int i = 1; i <20 ; i++) {
//开启多线程
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},"A").start();
}
}
}
结果
多线程下得集合不安全。
解决方法一:。会想到使用vector<>()。我今天在看源码得时候才发现原来vector 要比Arrlist 先出来


package com.jj.demo.listdemo;
import java.util.ArrayList;
import java.util.UUID;
import java.util.Vector;
/**
* @author fjj
* @date 2021/3/20 15:51
*/
public class ListDemo {
public static void main(String[] args) {
//创建集合类
Vector<String> list = new Vector<>();
//循环放入数据
for (int i = 1; i <20 ; i++) {
//开启多线程
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},"A").start();
}
}
}
用这个集合类解决了并发情况下得安全问题。没有异常。不过,因为是 被synchronized 修饰。效率可能就不快了
解决方法二: 使用工具类来解决并发不安全得问题
package com.jj.demo.listdemo;
import java.util.*;
/**
* @author fjj
* @date 2021/3/20 15:51
*/
public class ListDemo {
public static void main(String[] args) {
//创建集合类
List<String> list = Collections.synchronizedList(new ArrayList<>());
//循环放入数据
for (int i = 1; i <20 ; i++) {
//开启多线程
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},"A").start();
}
}
}
通过工具类来加上同步代码块。效率还是不高。
解决方法四: 我们可以用 CopyOnWrite 写入时复制。COW 计算机程序设计得一种优化策略;多个线程
调用得时候,List 读取的时候,固定得,写入(覆盖),再写入得时候避免覆盖,造成数据问题!
package com.jj.demo.listdemo;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @author fjj
* @date 2021/3/20 15:51
*/
public class ListDemo {
public static void main(String[] args) {
//创建集合类
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
//循环放入数据
for (int i = 1; i <20 ; i++) {
//开启多线程
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},"A").start();
}
}
}
他得add 方法得源码
Set 集合不安全
package com.jj.demo.Setdemo;
import java.util.HashSet;
import java.util.UUID;
/**
* @author fjj
* @date 2021/3/20 16:37
*/
public class SetDemo {
public static void main(String[] args) {
//创建Set 集合
HashSet<Object> set = new HashSet<>();
for (int i = 1; i <20 ; i++) {
//开启多线程
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},"A").start();
}
}
}
与上面一样,解决方法我们可以用CopyOnWrite
package com.jj.demo.Setdemo;
import java.util.HashSet;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @author fjj
* @date 2021/3/20 16:37
*/
public class SetDemo {
public static void main(String[] args) {
//创建Set 集合
CopyOnWriteArraySet<Object> set = new CopyOnWriteArraySet<>();
for (int i = 1; i <20 ; i++) {
//开启多线程
new Thread(()->{
set.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(set);
},"A").start();
}
}
}
HahSet 得底层是Hash Map
Map 集合得使用
package com.jj.demo.HahMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author fjj
* @date 2021/3/20 16:53
*/
public class HashMap {
public static void main(String[] args) {
//创建线程
ConcurrentHashMap<Object, Object> hashMap = new ConcurrentHashMap<>();
for (int i = 1; i < 400; i++) {
new Thread(()->{
hashMap.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0,5));
System.out.println(hashMap);
},"A").start();
}
}
}
ConcurrentHashMap实现得原理
1)ConcurrentHashMap使用分段技术,将数据分为一段一段得存储。给每一段数据配置一把锁,当一个锁占用锁访问其中一段数据时,其他段得数据也能被其他线程访问了。
2)ConcurrentHashMap 是一个线程安全得哈希表,她得主要功能是提供一组和HashMap 功能相同但是线程安全得方法。
3)工作原理:
ConcurrentHashMap为了提高本身得并发能力,在内部采用了一个叫做Segment 得结构,一个Segment 其实就是一个类Hash Table 得结构,Segment 内部维护一个链表数组。
Callable 类得使用
package com.jj.demo.Callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @author fjj
* @date 2021/3/20 17:38
*/
public class CallableDemo {
//获取 Callable 线程
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable1 callable1 = new Callable1();
//获取适配器
FutureTask task = new FutureTask(callable1);
//获取线程
new Thread(task,"A").start();
//获取返回值
Object o = task.get();
System.out.println("o = " + o);
}
}
class Callable1 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("我是call 方法");
return 1111;
}
}
相当于找了个中间商
结果
"C:\Program Files\Java\jdk1.8.0_231\bin\java.exe" "-javaagent:D:\idea\IntelliJ IDEA 2019.3.5\lib\idea_rt.jar=55948:D:\idea\IntelliJ IDEA 2019.3.5\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_231\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_231\jre\lib\rt.jar;E:\实习的代码\Demo\target\classes;E:\maven_jar包\org\openjdk\jmh\jmh-core\1.23\jmh-core-1.23.jar;E:\maven_jar包\net\sf\jopt-simple\jopt-simple\4.6\jopt-simple-4.6.jar;E:\maven_jar包\org\apache\commons\commons-math3\3.2\commons-math3-3.2.jar" com.jj.demo.Callable.CallableDemo
我是call 方法
o = 1111
Process finished with exit code 0
**JUC 的常用辅助类 **
CountDownLatch
package com.jj.demo.Callable;
import java.util.concurrent.CountDownLatch;
/**
* @author fjj
* @date 2021/3/20 19:56
*/
//计数器类
public class CountDownLatchDemo {
public static void main(String[] args) throws InterruptedException {
//总数是6
CountDownLatch countDownLatch = new CountDownLatch(6);
for (int i = 1; i < 7; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName());
//数量减少1
countDownLatch.countDown();
},String.valueOf(i)).start();
}
//等待计数器归零,然后再向下执行
countDownLatch.await();
System.out.println("结束");
}
}
CyclicBarrier 类
package com.jj.demo.Callable;
import java.util.concurrent.CyclicBarrier;
/**
* @author fjj
* @date 2021/3/20 20:01
*/
//数量增加
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
System.out.println("成功!");
});
for (int i = 1; i < 7; i++) {
final int tem =i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+tem);
}).start();
}
}
}
Semaphore 类
package com.jj.demo.Callable;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* @author fjj
* @date 2021/3/20 20:21
*/
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3);
for (int i =1; i <6 ; i++) {
new Thread(()->{
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"拿到了");
TimeUnit.SECONDS.sleep(2);
System.out.println(Thread.currentThread().getName()+"离开车位");
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
semaphore.release();
}
}).start();
}
}
}
ReadWriteLock 的案例
package com.jj.demo.ReadWriteLock;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @author fjj
* @date 2021/3/20 20:42
*/
public class ReadWriteLockDemo {
public static void main(String[] args) {
//获取缓存类
Cache cache = new Cache();
//开启写多线程
for (int i = 1; i < 5; i++) {
final int tem=i;
new Thread(()->{
cache.writ(tem,tem);
},String.valueOf(i)).start();
}
//开启读多线程
for (int i = 1; i < 5; i++) {
final int tem=i;
new Thread(()->{
cache.read(tem);
},String.valueOf(i)).start();
}
}
}
//自定义缓存类
class Cache{
//定义一个Map
private volatile Map<Integer,Object> map= new HashMap<>();
//定义一个读写锁
ReadWriteLock lock = new ReentrantReadWriteLock();
//写的方法
public void writ(Integer key,Object value){
//加锁
lock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"写入"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入ok");
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放锁
lock.writeLock().unlock();
}
}
//读的方法
public void read(Integer key){
//加锁
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName()+"读取"+key);
map.get(key);
System.out.println(Thread.currentThread().getName()+"读取ok");
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放锁
lock.readLock().unlock();
}
}
}
结果
BlockingQueue 四组API
第一组:抛出异常的 ,当我们的队列满了之后抛出异常
package com.jj.demo.mq;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
/**
* @author fjj
* @date 2021/3/21 15:54
*/
public class Demo1 {
public static void main(String[] args) {
test1();
}
public static void test1(){
//创建队列
ArrayBlockingQueue deque = new ArrayBlockingQueue<>(3);
//添加数据
System.out.println(deque.add("a"));
System.out.println(deque.add("b"));
System.out.println(deque.add("c"));
//检查队首元素
System.out.println(deque.element());
//读取数据
System.out.println(deque.remove());
System.out.println(deque.remove());
System.out.println(deque.remove());
}
}
上面我们代码如果超过我们的队列就会抛出来异常。很不友好
方法二,我们可以用有返回值的参数
public static void test2(){
ArrayBlockingQueue<Object> queue = new ArrayBlockingQueue<>(3);
//添加元素
System.out.println(queue.offer("1"));
System.out.println(queue.offer("2"));
System.out.println(queue.offer("3"));
System.out.println(queue.offer("4"));
//检查首位元素
System.out.println(queue.peek());
//取出元素
System.out.println(queue.poll());
}
**方法三 阻塞状态 **
public static void test3() throws InterruptedException {
//获取队列
ArrayBlockingQueue<Object> queue = new ArrayBlockingQueue<>(3);
//添加
queue.put("A");
queue.put("B");
queue.put("C");
//取出
System.out.println(queue.take());
}
方法四:超时等待状态
public static void test4() throws InterruptedException {
//创建队列
ArrayBlockingQueue<Object> queue = new ArrayBlockingQueue<>(3);
//添加
System.out.println(queue.offer("a"));
System.out.println(queue.offer("a"));
System.out.println(queue.offer("a"));
System.out.println(queue.offer("a",2, TimeUnit.SECONDS));
}
超过2s 就不会在添加,就不会傻等了。
线程池
线程池:三大方法,7大参数,4种拒绝策略
池化技术
程序的运行,本质:占用系统的资源!,优化资源的使用
线程池,连接池,内存池,对象池///… 创建,销毁,十分浪费资源
池化技术:事先准备好一些资源,有人要用,就来拿,用完还回去
线程池的好处
1,降低资源的消耗
2,提高响应的速度
3,方便管理
线程复用,可以控制最大的并发数,管理线程
线程的三大方法
package com.jj.demo.mq;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author fjj
* @date 2021/3/21 17:32
*/
public class Demo2 {
public static void main(String[] args) {
//方法一,单个线程
ExecutorService executor = Executors.newSingleThreadExecutor();
//方法二,创建一个固定的线程池的大小
ExecutorService executorService = Executors.newFixedThreadPool(5);
//方法三 可伸缩,遇强则强,
ExecutorService executorService1 = Executors.newCachedThreadPool();
try {
for (int i = 0; i < 10; i++) {
//使用了线程池之后,使用线程池来创建线程
executor.execute(()->{
System.out.println(Thread.currentThread().getName());
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池使用完毕后关闭
executor.shutdown();
}
}
}
自定义线程池和四种拒绝策略
一般情况不能直接用工具类做线程池,我们应该用他底层的实现
package com.jj.demo.mq;
import java.util.concurrent.*;
/**
* @author fjj
* @date 2021/3/21 17:32
*/
public class Demo2 {
public static void main(String[] args) {
//自定义线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
try {
for (int i = 0; i < 10; i++) {
//使用了线程池之后,使用线程池来创建线程
executor.execute(()->{
System.out.println(Thread.currentThread().getName());
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//线程池使用完毕后关闭
executor.shutdown();
}
}
}

四种拒绝策略
*/
// new ThreadPoolExecutor.AbortPolicy() 如果现在业务满了,还有人过来。抛出异常
// new ThreadPoolExecutor.CallerRunsPolicy() //哪里来的回到那里去
// ThreadPoolExecutor.DiscardPolicy() //队列满了,丢掉任务,不会抛出异常
//new ThreadPoolExecutor.DiscardOldestPolicy() 队列满了,尝试跟最早的竞争,也不会抛出异常