JUC一
Posted tianxc
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC一相关的知识,希望对你有一定的参考价值。
正式学习的准备工作
JUC并发编程
1.什么是JUC
JUC就是java.util .concurrent工具包的简称。这是一个处理线程的工具包,JDK 1.5开始出现的。
2.进程和线程回顾
什么是进程和线程?
进程:是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个独立单位,是应用,例如:QQ.exe
线程:是拥有资源和独立运行的最小单位,也是程序执行的最小单位.
一个进程可以包含多个线程,一个进程至少有一个线程!Java程序至少有两个线程:GC,main
并发、并行
并发:多个线程操作同一个资源,交替执行的过程!
并行:多个线程同时执行!只有在多核CPU下才能完成!
使用多线程或者并发编程的目的:提高效率,让CPU一直工作,达到最高处理性能!
线程有几种状态
线程有6种状态
public enum State {
// java能够创建线程吗? 不能!
// 新建
NEW,
// 运行
RUNNABLE,
// 阻塞
BLOCKED,
// 等待
WAITING,
// 延时等待
TIMED_WAITING,
// 终止!
TERMINATED;
}
Java不能够创建线程!!!(线程是操作系统的资源)
线程的状态切换
wait/sleep的区别
1、类不同!
wait——Object类 sleep——Thread类
在juc编程中,线程休眠怎么实现?
//时间单位
TimeUnit.SECONDS.sleep(3);
?
2、会不会释放资源
sleep:抱着锁睡得,不会释放锁;wait会释放锁。
3、使用的范围是不同的
wait和notify是一组,一般在线程通信的时候使用;
sleep就是一个单独的方法,在哪里都可以调用。
4、关于异常
sleep需要捕获异常
3.Lock锁
synchronized 传统的方式
代码:
package com.rudd.demo;
?
import java.util.concurrent.TimeUnit;
?
/**
* 传统的synchronized
* 企业级开发:
* 1.架构:高内聚,低耦合
* 2.套路:线程操作资源类,资源类是单独的。
*/
public class Test1 {
?
public static void main(String[] args) {
//1.新建资源类
Ticket ticket = new Ticket();
//2.线程操纵资源类
new Thread(()->{
for (int i = 1; i < 41; i++) {
ticket.saleTicket();
}
},"A").start();
new Thread(()->{
for (int i = 1; i < 41; i++) {
ticket.saleTicket();
}
},"B").start();
new Thread(()->{
for (int i = 1; i < 41; i++) {
ticket.saleTicket();
}
},"C").start();
}
}
//单独的资源类应该只有:属性和方法
class Ticket{
?
private int number = 30;
?
//synchronized 关键字
public synchronized void saleTicket(){
if(number>0){
System.out.println(Thread.currentThread().getName()+"卖出第"+(number--)+"票,还剩:"+number);
}
}
}
Lock锁
代码:
package com.rudd.demo;
?
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
?
public class Test02 {
?
public static void main(String[] args) {
//1.新建资源类
Ticket2 ticket = new Ticket2();
//2.线程操纵资源类,所有的函数式接口都可以用lambda表达式简化
//lambda表达式:(参数)->{具体的代码}
new Thread(()->{
for (int i = 1; i < 41; i++) {
ticket.saleTicket();
}
},"A").start();
new Thread(()->{
for (int i = 1; i < 41; i++) {
ticket.saleTicket();
}
},"B").start();
new Thread(()->{
for (int i = 1; i < 41; i++) {
ticket.saleTicket();
}
},"C").start();
}
}
?
class Ticket2{
/*
* 使用Lock,它是一个对象
* ReentrantLock 可重入锁
* ReentrantLock 默认是非公平锁
* 非公平锁:不公平(插队,后面的线程可以插队)
* 公平锁:公平(只能排队,后面的线程无法插队)
*/
private Lock lock = new ReentrantLock();
private int number = 30;
?
public 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的区别
-
synchronized是一个关键字;Lock是一个对象
-
synchronized无法尝试获取锁,Lock可以尝试获取锁,会进行判断;
-
synchronized会自动释放锁(a线程执行完毕,b如果异常了,也会释放锁),Lock锁是手动释放锁,如果不释放就会死锁。
-
synchronizedsynchronizedsynchronized(线程A(获得锁,如果阻塞),线程B(等待,一直等待));Lock可以尝试获取锁,失败了之后就放弃。
-
synchronized一定是非公平的锁,但是Lock锁可以是公平的,通过参数设置;
-
代码量特别大的时候,我们一般使用Lock实现精准控制,synchronized适合代码量较小的同步问题。
4.生产者和消费者
线程和线程之间本来是不能通信的,但是有时候我们需要线程之间可以协调操作:等待唤醒机制
synchronized
package com.rudd.demo;
/*
synchronized
?
目的:有两个线程:A B,还有一个初始值为0的变量
实现两个线程交替执行,对该变量进行+1和-1操作,交替10次。
?
传统的wait和notify方法不能实现精准唤醒。
*/
public class Test03 {
public static void main(String[] args){
Data data = new Data();
//负责+1操作
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
}catch (Exception e){
e.printStackTrace();
}
}
},"A").start();
//负责-1操作
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
}catch (Exception e){
e.printStackTrace();
}
}
},"B").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.increment();
}catch (Exception e){
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 10; i++) {
try {
data.decrement();
}catch (Exception e){
e.printStackTrace();
}
}
},"D").start();
}
}
?
//资源类
//线程之间的通信:判断 执行 通知
class Data{
private int number = 0;
?
public synchronized void increment() throws Exception{
//不要用if,会导致需要唤醒
while(number!=0){//1.判断是否需要等待
this.wait();
}
number++;//2.执行
System.out.println(Thread.currentThread().getName()+":::"+number);
this.notifyAll();//3.通知:唤醒所有线程
}
?
public synchronized void decrement() throws Exception{
//不要用if,会导致需要唤醒
while(number!=1){//1.判断是否需要等待
this.wait();
}