学姐天天缠着问我JUC,搞得我没有时间打游戏,无奈之下我写下JUC基础,要她自己去研究 上
Posted Code_BinBin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学姐天天缠着问我JUC,搞得我没有时间打游戏,无奈之下我写下JUC基础,要她自己去研究 上相关的知识,希望对你有一定的参考价值。
引言
今天是星期一,翘了课在寝室玩农药,正当我要五杀的时候,学姐给我打了个电话,于是我的五杀没了。
“学弟,今天面试官问我了不了解JUC,没答出来怎么办?”学姐哭着问道
“面试官怎么说的啊?”我把自己痛失五杀的愤怒强行压制下去,毕竟这个是在我大一的时候对我照顾有加的学姐,无论是正常的校园生活和不正常的校园生活,要我舒舒服服的混到了大三,是、人要有一颗感恩的心,所以我还是忍住没有和她发脾气。
“面试官说日后再说”,学姐说道
“这样的吗?这个面试官可真不是什么好东西?”
“为什么这么说啊”?学姐不解的说道。
“没事学姐,我给你写一篇JUC的文章,你有时间看看就好了”
什么是 JUC
JUC就是 java.util 下的工具包、包、分类等。
“在我们学习JUC之前,先去回顾一下线程方面的知识,学姐你要是不会的话可以子去看一下别的博主的博客,我以后有时间会写”,我说道
“好的学弟”
普通的线程
- Thread
- Runnable 没有返回值、效率相比入 Callable 相对较低!
- Callable 有返回值!
线程和进程
我之前就有写过一篇关于线程和进程的文章,可以先看看这篇文章
- 进程:一个程序,QQ.exe Music.exe 程序的集合;
- 一个进程往往可以包含多个线程,至少包含一个
- Java默认有2个线程? mian、GC
- 线程:开了一个进程 Typora,写字,自动保存(线程负责的)
- 对于Java而言提供了:Thread、Runnable、Callable操作线程。
并发、并行
并发
当我们有若干个线程需要运行的时候,由于cpu处理速度很快,他会把若干个线程快速交替,就是多线程同时操作资源
并行
假如我们的电脑是36核的,36个cpu同时运行
可以用这个代码来检查一下自己电脑是几核的,我的是16核
public class Test1 {
public static void main(String[] args) {
// 获取cpu的核数
// CPU 密集型,IO密集型
System.out.println(Runtime.getRuntime().availableProcessors());
// 如果电脑是8核,则结果输出8
}
}
注:
并发编程的本质就是充分利用CPU的资源
线程有几个状态
答案:6个
public enum State {
/**
* Thread state for a thread which has not yet started.
* 线程新生状态
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
* 线程运行中
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
* 线程阻塞状态
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
* 线程等待状态,死等
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
* 线程超时等待状态,超过一定时间就不再等
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
* 线程终止状态,代表线程执行完毕
*/
TERMINATED;
}
wait/sleep 区别
第一:两者来自不同的父类
- wait => Object
- sleep => Thread
第二:两者释放锁不一样
- wait 会释放锁
- sleep 睡觉了,抱着锁睡觉,不会释放!
第三:两者使用的范围是不同的
- wait 必须在同步代码块中使用
- sleep 可以再任何地方睡眠
Synchronized锁
传统 Synchronized锁:一个简单的卖票例子
package com.znb;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test01 {
public static void main(String[] args) {
//并发:多个线程同时操作一个资源类,把资源类丢入线程
Ticket ticket = new Ticket();
// @FunctionalInterface 函数式接口,jdk1.8 lambada表达式
new Thread(() -> {
for (int i = 1; i < 50; i++) {
ticket.sale();
}
}, "A").start();
new Thread(() -> {
for (int i = 1; i < 50; i++) {
ticket.sale();
}
}, "B").start();
new Thread(() -> {
for (int i = 1; i < 50; 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() + "卖出了" +
(50-(--number)) + "张票,剩余:" + number + "张票");
}
}
}
Lock锁
公平锁(FairLock)
十分公平,分先来后到,不准插队
非公平锁 (UnFairLock)
不公平,可以插队
一般都是默认非公平锁,因为有时候如果一个线程的延时是10分钟,另一个线程没有延时,如果延时十分钟的线程先到,那么后一个线程就要等十分钟。
将上面的卖票例子用lock锁 替换synchronized:
package com.znb;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test01 {
public static void main(String[] args) {
Ticket ticket=new Ticket();
new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.sale();
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.sale();
}},"B").start();
new Thread(()->{
for (int i = 0; i < 40; i++) {
ticket.sale();
}},"C").start();
}
}
class Ticket{
private int number =100;
Lock lock=new ReentrantLock();
public synchronized void sale(){
if (number>0){
System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"张票子");
}
}
}
Synchronized 和 Lock 区别:
- Synchronized 内置的Java关键字, Lock 是一个Java类
- Synchronized 可重入锁,不可以中断的,非公平;Lock ,可重入锁,可以判断锁,非公平(可以自己设置)
- Synchronized 无法判断获取锁的状态,Lock 可以判断是否获取到了锁
- Synchronized 会自动释放锁,lock 必须要手动释放锁!如果不释放锁,就会死锁
- Synchronized 适合锁少量的代码同步问题,Lock 适合锁大量的同步代码
- Synchronized 线程 1(获得锁,如果线程1阻塞)、线程2(等待);Lock锁就不一定会等待下去;
生产者和消费者问题
非JUC版
可以参考一下我之前的博客
package com.znb.pc;
public class Test01 {
public static void main(String[] args) {
A a=new A();
new Thread(()->{
for (int i = 0; i < 100; i++) {
try {
a.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 100; i++) {
try {
a.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 100; i++) {
try {
a.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
new Thread(()->{
for (int i = 0; i < 100; i++) {
try {
a.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
class A{
private int sum=0;
public synchronized void incr() throws InterruptedException {
while(sum!=0){
this.wait();
}
sum++;
System.out.println(Thread.currentThread().getName()+"==》"+sum);
this.notifyAll();
}
public synchronized void decr() throws InterruptedException {
while (sum==0){
this.wait();
}
sum--;
System.out.println(Thread.currentThread().getName()+"==》"+sum);
this.notifyAll();
}
}
这里我们通过线程A唤醒B,B唤醒C以此类推,并且这里我们用的是while,因为如果我们用的是if,并且线程大于2个,那么就会存在虚假唤醒,出现错误
使用while的结果
使用if的结果
我们可以看见,出现了-169,-170这样错误的数据,所以这里记得用while
JUC版
这里引进一个新东西,叫Condition
代码实现
package com.znb.pc;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test02 {
public static void main(String[] args) {
B a=new B();
new Thread(()->{
for (int i = 0; i < 100; i++) {
try {
a.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"A").start();
new Thread(()->{
for (int i = 0; i < 100; i++) {
try {
a.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"C").start();
new Thread(()->{
for (int i = 0; i < 100; i++) {
try {
a.incr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"D").start();
new Thread(()->{
for (int i = 0; i < 100; i++) {
try {
a.decr();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"B").start();
}
}
class B{
private int sum=0;
Lock lock=new ReentrantLock();
Condition condition=lock.newCondition();
public void incr() throws InterruptedException {
lock.lock();
try {
while(sum!=0){
condition.await();
}
sum++;
System.out.println(Thread.currentThread().getName()+"==》"+sum);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void decr() throws InterruptedException {
lock.lock();
try {
while (sum==0){
condition.await();
}
sum--;
System.out.println(Thread.currentThread().getName()+"==》"+sum);
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
当我们使用Condition 的时候,我们唤醒线程和要线程等待就不是用什么 wait,sleep ,notifyAll这些东西了,我们需要使用 await 等待,signalAll唤醒
但是细心的我们发现,我们线程的顺序是A->B->C->D,但是最后输出的答案并不是这样,那要怎么办呢?没关系JDK源码的作者也想到了这个问题。
package com.znb.pc;
import java.util.concurrent.locks.Condition以上是关于学姐天天缠着问我JUC,搞得我没有时间打游戏,无奈之下我写下JUC基础,要她自己去研究 上的主要内容,如果未能解决你的问题,请参考以下文章