赞
踩
本笔记仅做学习与复习使用,不存在刻意抄袭。
------------------------------------------------------------------------------------------------------------
给各位学友强烈推荐《遇见狂神说》他的整套Java学习路线使我获益匪浅!!!
如果你也是狂神的小迷弟,可以加我好友一起探讨学习。
JUC就是java.util.concurrent包,俗称java并发包,是Java开发工程师学习并发的时候需要掌握的内容。
我认为起码有以下几点:
接下来就是《狂神说Java》JUC并发编程的课程笔记和我自己的总结了,或许,没有看视频的学友看着会觉得有些混乱或者逻辑错误。这里还是强调一点,各位最好是配合视频学习,笔记只当作初学或者今后复习就好。
源码+官方文档(面试高频)
这里简述一下juc在jdk帮助文档的位置(jdk帮助文档请自行百度下载):
我们打开jdk帮助文档
点击左侧目录:
我们按住ctrl加鼠标左键,点击Thread :
跳转到:
可以看到其实现了Runnable接口。
这里简单写个小例子回忆一下继承Thread类如何使用。
- package com.example.demo1.demo02;
- /**
- * @author liar
- */
- public class TestThread {
- public static void main(String[] args) {
- Eat eat = new Eat();
- Out out = new Out();
- eat.start();
- out.start();
- }
- }
- class Eat extends Thread{
- @Override
- public void run() {
- for (int i = 0; i < 500; i++) {
- System.out.println( "我在吃饭呢");
- }
- }
- }
- class Out extends Thread{
- @Override
- public void run() {
- for (int i = 0; i < 500; i++) {
- System.out.println("我在拉屎呢");
- }
- }
- }
其核心是重写run方法;其运行结果是:
- package com.example.demo1.demo02;
-
- /**
- * @author liar
- */
- public class TestRunnable {
- public static void main(String[] args) {
- Who who = new Who();
- FBI fbi = new FBI();
- Thread who1 = new Thread(who,"who");
- Thread fbi1 = new Thread(fbi,"FBI");
- who1.start();
- fbi1.start();
- }
- }
- class Who implements Runnable{
- @Override
- public void run() {
- for (int i = 0; i < 1000; i++) {
- System.out.println("Who are you ?");
- }
- }
- }
- class FBI implements Runnable{
- @Override
- public void run() {
- for (int i = 0; i < 1000; i++) {
- System.out.println("Open the door!!!FBI!!!");
- }
- }
- }
运行结果也如预期。
- package com.example.demo1.demo02;
-
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.FutureTask;
-
- public class TestCallable {
- public static void main(String[] args) {
- Hit hit = new Hit();
- Connection connection = new Connection();
- FutureTask futureTask1 = new FutureTask(hit);
- FutureTask futureTask2 = new FutureTask(connection);
- Thread t1 = new Thread(futureTask1);
- Thread t2 = new Thread(futureTask2);
- t1.start();
- t2.start();
- try {
- //get()方法的返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值
- Object o1 = futureTask1.get();
- Object o2 = futureTask2.get();
- System.out.println(o1);
- System.out.println(o2);
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
- }
- class Hit implements Callable{
- @Override
- public Object call() throws Exception {
- for (int i = 0; i < 500; i++) {
- System.out.println("怎么样!!你打我啊!!!");
- }
- return "hit";
- }
- }
- class Connection implements Callable{
- @Override
- public Object call() throws Exception {
- for (int i = 0; i < 500; i++) {
- System.out.println("小伙子,出来混,是要讲人脉的!!!");
- }
- return "connection";
- }
- }
其运行结果:
其与前两者的区别是,可以通过FutureTask获取返回值的。
普通的线程代码:继承Thread类
Runnable接口:没有返回值,效率相比于Callable接口较低
关于线程和进程,如果不能用一句话说出来,说明你掌握的还不够扎实!
进程:
Java真的能开启线程吗?
并发:(多线程操作同一资源)
并行:(多个人同时走路)
并发编程的本质:充分利用CPU的资源
- public enum State {
- NEW,//新生
-
- RUNNABLE,//运行
-
- BLOCKED,//阻塞
-
- WAITING,//等待,一直等待
-
- TIMED_WAITING,//超时等待,过期不候
-
- TERMINATED;//终止
- }
来自不同的类:
关于锁的释放
使用的范围是不同的
是否需要捕获异常
作用:
保证线程安全,例如当多个线程访问统一资源时,会发生数据紊乱问题;
怎么理解:
队列+锁
实例:没有synchronized修饰的方法
- package com.example.demo1.demo02;
- /**
- * @author liar
- */
- public class UnsafeTicket {
- public static void main(String[] args) {
- BuyTicket ticket = new BuyTicket();
- new Thread(ticket,"倒霉的我").start();
- new Thread(ticket,"幸运的你们").start();
- new Thread(ticket,"可恶的黄牛党").start();
- }
- }
- class BuyTicket implements Runnable{
- private int tickets = 10;
- private boolean flag = true;
- @Override
- public void run() {
- while (flag){
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- buy();
- }
- }
- //在方法名前加上"synchronized",那么该方法就变成了同步方法了
- //!!!锁的是"this"!!!
- //'synchronized'默认锁的是this
- private synchronized void buy(){
- if (tickets<=0){
- flag=false;
- //这个return放在这里,如果符合if条件,那么返回出去,不执行下面的sout语句
- return;
- }
- System.out.println(Thread.currentThread().getName()+"买到了第"+tickets--+"张票");
- }
- }
-
我们看一下运行效果:
实例:有synchronized修饰的方法
- package com.example.demo1.demo02;
- /**
- * @author liar
- */
- public class UnsafeTicket {
- public static void main(String[] args) {
- BuyTicket ticket = new BuyTicket();
- new Thread(ticket,"倒霉的我").start();
- new Thread(ticket,"幸运的你们").start();
- new Thread(ticket,"可恶的黄牛党").start();
- }
- }
- class BuyTicket implements Runnable{
- private int tickets = 10;
- private boolean flag = true;
- @Override
- public void run() {
- while (flag){
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- buy();
- }
- }
- //在方法名前加上"synchronized",那么该方法就变成了同步方法了
- //!!!锁的是"this"!!!
- //'synchronized'默认锁的是this
- private synchronized void buy(){
- if (tickets<=0){
- flag=false;
- //这个return放在这里,如果符合if条件,那么返回出去,不执行下面的sout语句
- return;
- }
- System.out.println(Thread.currentThread().getName()+"买到了第"+tickets--+"张票");
- }
- }
-
这下,就是线程安全的了。
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
-
- //基本的卖票例子
- /*
- 真正的多线程开发,公司中的开发,降低耦合性
- 线程就是一个单独的资源类,没有任何附属操作
- 1、属性、方法
- */
- public class SaleTicketDemo2 {
- public static void main(String[] args) {
- //并发:多线程操作同一个类,把资源类丢入线程
- Ticket2 ticket = new Ticket2();
- //@FunctionalInterface 函数式接口,jdk1.8 lambda表达式 (参数)->{代码}
- new Thread( () ->{
- for (int i = 0; i < 40; i++) {
- ticket.sale();
- }
- },"A").start();
- new Thread( () ->{
- for (int i = 0; i < 40; i++) {
- ticket.sale();
- }
- },"B").start();
- new Thread( () ->{
- for (int i = 0; i < 40; i++) {
- ticket.sale();
- }
- },"C").start();
-
- }
- }
-
- //Lock三部曲
- //1.new ReentrantLock();
- //2. lock.lock(); 加锁
- //3.finally --> lock.unlock(); 解锁
- class Ticket2{
- //属性方法
- private int number = 50;
- Lock lock = new ReentrantLock();
-
- public void sale(){
- lock.lock(); //加锁
-
- try{
- //业务代码
- if(number > 0){
- System.out.println(Thread.currentThread().getName() + "卖出了" + (number--) + "票,剩余" + number);
- }
- }catch (Exception e){
- e.printStackTrace();
- }finally {
- //解锁
- lock.unlock();
- }
-
- }
- }
1、Synchronized内置的Java关键字,Lock是一个Java类
2、Synchronized无法判断获取锁的状态,Lock可以判断是否获取到了锁
3、Synchronized是全自动的,会自动释放锁,Lock必须要手动释放锁,如果不释放锁,死锁
4、Synchronized 线程1(获得锁,阻塞)、线程2(等待,傻傻的等);Lock锁就不一定会等待下去
5、Synchronized可重入锁,不可以中断,非公平;Lock可重入锁,可以判断锁,非公平(可以自己设置)
6、Synchronized适合锁少量的代码同步问题,Lock适合锁大量的同步代码
锁是什么?如何判断锁的是谁?
面试:单例模式、排序算法、生产者和消费者问题、死锁
- package com.my.pc;
- /*
- * 线程之间的通信问题:生产者和消费者问题(等待唤醒,通知唤醒)
- *
- * 线程交替执行:
- * 生产者和消费者操作同一个变量
- * 生产者:+1
- * 消费者:-1
- * */
- public class Test {
- public static void main(String[] args) {
- Data data = new Data();
-
- new Thread(()->{
- try {
- for (int i = 0; i < 10; i++) {
- data.increment();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- },"生产者").start();
-
- new Thread(()->{
- try {
- for (int i = 0; i < 10; i++) {
- data.decrement();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- },"消费者").start();
- }
- }
-
- //资源类
- /*
- * 编写资源类的思路:
- * 判断等待、业务、通知
- * */
- class Data{
- private int number = 0;
-
- public synchronized void increment() throws InterruptedException {
- if (number!=0){
- //生产者等待
- this.wait();
- }
- number++;
- System.out.println(Thread.currentThread().getName()+"=>"+number);
- //唤醒消费者进程进行“消费”
- this.notifyAll();
- }
-
- public synchronized void decrement() throws InterruptedException {
- if (number==0){
- //消费者等待
- this.wait();
- }
- number--;
- System.out.println(Thread.currentThread().getName()+"=>"+number);
- //唤醒生产者进程进行“生产”
- this.notifyAll();
- }
-
- }
这样会出现问题!!–虚假唤醒
场景:当出现多个生产者和消费者时,会出现数据紊乱?
原因:就是这个if语句只判断一次:当消费者线程阻塞,来唤醒生产者线程时,多个生产者线程都会被唤醒,但是只有第二个生产者线程执行了if判断,然后第二个生产者线程阻塞(基于if语句的机理),因为第一个生产者线程能够正常执行,而剩余的其他生产者线程,则会执行if语句后面的方法(“意思就是后面的生产者线程在if判断前面生产者线程时,利用了if语句的bug捡了漏”)
(1)if判断流水线状态为空时,线程被阻塞,这时if判断就完成了,线程被唤醒后直接执行线程剩余操作
(2)while判断流水线状态为空时,线程被阻塞,这时的while循环没有完成,线程被唤醒后会先进行while判断
解决方法:
把if语句改为while语句
- package com.my.pc;
- /*
- * 线程之间的通信问题:生产者和消费者问题(等待唤醒,通知唤醒)
- *
- * 线程交替执行:
- * 生产者和消费者操作同一个变量
- * 生产者:+1
- * 消费者:-1
- * */
- public class Test {
- public static void main(String[] args) {
- Data data = new Data();
-
- new Thread(()->{
- try {
- for (int i = 0; i < 10; i++) {
- data.increment();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- },"生产者").start();
-
- new Thread(()->{
- try {
- for (int i = 0; i < 10; i++) {
- data.decrement();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- },"消费者").start();
-
- new Thread(()->{
- try {
- for (int i = 0; i < 10; i++) {
- data.decrement();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- },"C").start();
-
- new Thread(()->{
- try {
- for (int i = 0; i < 10; i++) {
- data.decrement();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- },"D").start();
- }
- }
-
- //资源类
- /*
- * 编写资源类的思路:
- * 判断等待、业务、通知
- * */
- class Data{
- private int number = 0;
-
- public synchronized void increment() throws Interrupted
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。