[笔记]跟着狂神学Java-多线程篇


线程/进程

 我的理解:电脑上执行的一个游戏窗口是一个进程,每个模式或者按钮是一个线程

继承Thread类

一个类继承了Thread类之后,可以重写Thread类中的run方法。
然后通过对该类实例化后的对象调用start() 方法来启动线程。
(当然别忘了导包哈~:java.lang.Thread)

public class TestThread extends Thread {@overridepublic void run() {//重写父类函数体}public static void main(String[] args) {TestThread th = new TestThread();th.start();}
}

实现Runnable 接口

一个类实现了Runnable接口之后,必须要实现Runnable接口中的run() 方法。(导包:java.lang.Runnable)
通过实例化该类创建一个对象来调用start() 方法来启动线程。
当然也可以这样来启动 new Thread(对象名).start

public class TestThread implements Runnable {@overridepublic void run() {//实现Runnable接口的run() 方法}public static void main(String[] args) {TestThread th = new TestThread();th.start();//new Thread(th).start;}
}

实现Callable 接口

因为我还没有学的特别深,目前觉得和Runnable接口差不多,但是会有执行之后的返回值。
(导包:java.util.concurrent.Callable)
具体实现有一下几个步骤:
1. 实现Callable 接口,需要返回值类型
2. 重写call() 方法,需要抛出异常
3. 创建目标对象
4. 创建执行服务
5. 提交执行
6. 获取结果
7. 关闭服务

public class TestThread implements Callable {//实现call() 方法@Overridepublic Object call() throws Exception {//call方法的返回值类型可以修改return null;}//这里也可以选择抛出最高Exceptionpublic static void main(String[] args) throws InterruptedException,ExecutionException  {//创建线程池ExecutorService service = Executor.newFixedThreadPool(10);//参数:线程数//创建目标对象TestThread th = new TestThread;//提交执行Future<Boolean> t1 = service.submit(th);Future<Boolean> t2 = service.submit(th);Future<Boolean> t3 = service.submit(th);//也可以这样写//Future<Boolean> t1 = service.submit(new TestThread);//获取结果,需要捕获或者抛出异常,这里我选择抛出System.out.println(t1.get());System.out.println(t2.get());System.out.println(t3.get());//关闭服务service.shutdownNow();}}

线程的并发

  • 并发
    多个线程一块启动,但是我们自己的电脑只有一个CPU,然而又因为CPU的执行速度比较快,多个线程看上去像是同时执行,但从围观的角度看是这些线程在交替执行,轮流被CPU处理,这叫并发。
  • 并行
    同一时刻多条线程在同时执行,一起被CPU所执行,因此需要多个CPU,这叫并发。

Lambda 表达式

了解函数式接口:

  • 只包含了一个抽象方法的接口叫做函数式接口
  • 对于函数式接口,我们可以通过Lambda表达式来创建该接口的对象。
public class TestLambda implements Lambda {@Overridepublic void lambda(int a) {System.out.println("This is Function lambda");}public static void main(String[] args) {Lambda myLambda = null;//写法一myLambda = (int a) -> {System.out.println("This is Test1");};//写法二myLambda = (a) -> {System.out.println("This is Test2");  };//写法三(箭头后面如果有多个语句,就必须要用{})myLambda = a -> System.out.println("This is Test3");}}

线程的五大状态及常用方法

1. sleep() 线程休眠
2. yield() 线程礼让
3. join() 强制执行线程
4. 观测线程状态
5. 线程的优先级
6. 守护线程

观测线程状态

  • Thread.State,State是Thread类中的一个枚举类,一共有六种状态:NEW(初始化,未启动状态),RUNNABLE(在JVM中执行的线程状态),BLOCKED(被阻塞,等待监视器锁定),WAITTING(等待另一个线程执行),TIME_WAITTING(等待另一个线程执行到指定时间),TERMINATED(已结束)。
//创建一个线程并启动/休眠
Thread thread = new Thread();
thread.start();
//thread.sleep();
//创建一个状态对象
Thread.State state = thread.getState();
//打印状态
System.out.println(state);

线程的优先级
(官方预设的三个优先级,线程不设置优先级默认是5)

  • Thread.MIN_PRIORITY = 1;
  • Thread.NORM_PRIORITY = 5;
  • Thread.MAX_PRIORITY = 10;

Thread thread = new Thread();
//参数可以填1-10的数字,也可以填上面三个预设好的常量
thread.setPriority(1);

守护线程

/*
* 用户线程->Son
* 守护线程->Father
* JVM必须确保用户线程执行完毕
* JVM不用等待守护线程执行完毕
* */public class ThreadDaemon {public static void main(String[] args) {Father father = new Father();Son son = new Son();//设置守护线程Thread thread = new Thread(father);thread.setDaemon(true);//启动线程thread.start();new Thread(son).start();}}class Father implements Runnable {@Overridepublic void run() {while(true){System.out.println("Father Protect Son");}}
}class Son implements Runnable {@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("Son is Happy!");}System.out.println("Life ------  Over");}
}

线程同步机制

1. 同步方法及同步块
2. 死锁
3. Lock 锁
  • 同步方法
    (synchronized 可重入锁)
public synchronized void method (int args) {}

会产生的问题:
1. 一个线程持有锁会导致其他所有需要此锁的线程挂起(阻塞)。
2. 多线程竞争下,加锁,释放锁会导致调度延时,引起性能问题。
3. 如果一个优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题。

  • 同步块
    我跟着狂神做了银行取钱的个小实例,我个人觉得讲的不错,自己加了点修改,因为我照着他打出来的代码老是只有一个线程独占。后来发现是循环的问题,他写的是一个线程执行到结束。
    这是我修改后的实例
package Syn;public class Application {public static void main(String[] args) {//创建账户Account account = new Account("结婚基金",1000);Bank you = new Bank(account, 50, "你");Bank wife = new Bank(account, 100, "老婆");you.setPriority(1);you.start();wife.setPriority(10);wife.start();}
}class Account {String name;int money;public Account(String name, int money) {this.name = name;this.money  = money;}
}class  Bank extends Thread {Account account;int drawingMoney;int currentMoney = 0;private boolean flag = true;public Bank(Account account, int drawingMoney, String name) {super(name);this.account = account;this.drawingMoney = drawingMoney;}//取钱@Overridepublic void run() {while (flag) {try {withDraw();Thread.sleep(100);} catch (Exception e) {e.printStackTrace();}}}private void withDraw () {synchronized (account) {//判断有没有钱if (account.money - drawingMoney < 0) {System.out.println(Thread.currentThread().getName() + "没钱了,取不了钱");flag = false;return;}//手里的钱currentMoney += drawingMoney;System.out.println(this.getName() + "取了 " + drawingMoney + " 现在手里有 " + currentMoney);//卡里余额account.money -= drawingMoney;System.out.println(account.name + "还剩 " + account.money);}}
}
  • 死锁
    在线程同步时,会产生死锁的问题。我的理解是一个线程X访问一个资源A的同时还需要去访问另外一份资源B。但是另外一份资源B被Y正在访问中,无法释放锁,同时线程Y也要继续访问资源A,但线程X正在访问,无法释放锁,所以产生了“死结”,谁也不让谁,就导致了线程的卡死。

      附上跟狂神一块敲的小实例:
    
package Syn;public class DeadLock {public static void main(String[] args) {MakeUp g1 = new MakeUp("灰姑娘", 0);MakeUp g2 = new MakeUp("公主", 1);g1.start();g2.start();}}class LipSticks {}class  Mirror {}class MakeUp extends Thread {//保证资源只有一份static LipSticks lipSticks = new LipSticks();static Mirror mirror = new Mirror();String name;int choice;MakeUp(String name, int choice) {this.name = name;this.choice = choice;}@Overridepublic void run() {makeUp();}private void makeUp() {if (choice == 0) {synchronized (lipSticks) {System.out.println(this.name+ "获得了口红锁");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}//将锁写在锁里面会发生死锁
//                synchronized (mirror) {//                    System.out.println(this.name + "获得了镜子锁");
//                }}//此时不会发生死锁synchronized (mirror) {System.out.println(this.name + "获得了镜子锁");}}else {synchronized (mirror) {System.out.println(this.name + "获得了镜子锁");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}//将锁写在锁里面会发生死锁
//                synchronized (lipSticks) {//                    System.out.println(this.name + "获得了口红锁");
//                }}//此时不会发生死锁synchronized (lipSticks) {System.out.println(this.name + "获得了口红锁");}}}}
  • Lock锁
    (可重入锁)
    跟(synchronized)锁功能差不多,比它更高效。
    小实例:
package Syn;import java.util.concurrent.locks.ReentrantLock;public class LockTest{public static void main(String[] args) {LockTest2 lockTest2 = new LockTest2();new Thread(lockTest2,"Thread 1").start();new Thread(lockTest2,"Thread 2").start();new Thread(lockTest2,"Thread 3").start();}
}class LockTest2 implements Runnable  {private int ticket = 100;//创建可重入锁private final ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while (true) {try {//加锁lock.lock();if (ticket > 0) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " Get " + ticket--);}else {break;}} finally {//解锁lock.unlock();}}}
}

线程协作

生产者和消费者问题
思想:消费者去商店排队买东西,若商店里面有商品,则生产者通知消费者可以开始消费了,若商品消费完毕,则消费者通知生产者生产商品。

解决方法:

1. 管程法
2. 信号灯法
  • 管程法
    利用缓冲区来完成协作
package TestPC;//消费者/生产者问题--->利用缓冲区解决,管程法
public class PcTest {public static void main(String[] args) {SynContainer container = new SynContainer();new Producer(container).start();new Consumer(container).start();}
}//消费者
class Consumer extends Thread {//创建一个容器SynContainer container;public Consumer (SynContainer container) {this.container = container;}//消费@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println("消费了 " + container.pop().id + " 块面包");}}
}//生产者
class Producer extends Thread {//创建一个容器SynContainer container;public Producer (SynContainer container) {this.container = container;}//生产@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println("生产了 " + i + " 块面包");container.push(new Goods(i));}}
}//产品
class Goods {int id;public Goods(int id) {this.id = id;}}//缓存区,消费发生地
class SynContainer {//创建容器大小Goods[] bread = new Goods[10];//商品计数器int count = 0;//生产者放入产品public synchronized void push(Goods goods) {//如果容器满了则通知消费者消费if (count == bread.length) {//通知消费者消费,生产等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果没满,则生产者丢入商品bread[count] = goods;count++;//通知消费者消费this.notifyAll();}//消费者消费商品public synchronized Goods pop() {//判断是否能够消费if (count == 0) {//等待生产者生产,消费者等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//消费者消费count--;Goods goods = bread[count];//商品消费完,通知生产者生产this.notifyAll();return goods;}
}
  • 信号灯法
    利用一个标志位flag来判断谁该等待从而达到协作
package TestPC;//消费者/生产者问题---->信号灯法解决
public class PcTest2 {public static void main(String[] args) {Bread bread = new Bread();new Baker(bread).start();new Customer(bread).start();}
}//生产者---->糕点师
class Baker extends Thread{Bread bread;public Baker(Bread bread) {this.bread = bread;}//糕点师生产@Overridepublic void run() {for (int i = 0; i < 20; i++) {if (i%2 == 0) {this.bread.produce("可颂");}else {this.bread.produce("法棍");}}}
}//消费者---->顾客
class Customer extends Thread{Bread bread;public Customer (Bread bread) {this.bread = bread;}//顾客买面包@Overridepublic void run() {for (int i = 0; i < 20; i++) {this.bread.buy();}}
}//产品----> 面包是否有存货作为控制消费和生产的条件
class Bread {//面包名字String cake;//判断是否有面包的存货boolean flag = true;//生产者生产中,顾客等待(生产)public synchronized void produce(String cake) {//顾客等待if (!flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//生产System.out.println("糕点师制作了:" + cake);//生产后通知消费者消费this.notifyAll();this.cake = cake;this.flag = !this.flag;}//顾客消费中,生产者等待(消费)public synchronized void buy () {//生产者等待if (flag) {try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//消费System.out.println("顾客买了:" + cake);//产品消费完,通知生产者生产this.notifyAll();this.flag = !this.flag;}
}
  • 线程池
//创建线程池
ExecutorService service = Executor.newFixedThreadPool(10);//参数:线程数

以上都是我跟着狂神学Java多线程时的一些代码和感悟,纯属当作笔记来分享,如果大家发现了我笔记中的错误,可以多多指正,我会认真修改,虚心求教的!(ps:第一次写博客,请多多见谅~)

【Java学习笔记】——多线程相关推荐

  1. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  2. Java学习笔记---多线程并发

    Java学习笔记---多线程并发 (一)认识线程和进程 (二)java中实现多线程的三种手段 [1]在java中实现多线程操作有三种手段: [2]为什么更推荐使用Runnable接口? [3][补充知 ...

  3. java学习笔记 多线程(一)创建多线程,线程常用方法

    首先是进程和线程的区别,进程就是像打开csgo.exe就是一个进程,然后打开LOL.exe又是另外一个进程了. 而线程呢,就是在同一进程内部,发生的事情. 那么就开始了解线程! 创建多线程: 线程有三 ...

  4. 0040 Java学习笔记-多线程-线程run()方法中的异常

    run()与异常 不管是Threade还是Runnable的run()方法都没有定义抛出异常,也就是说一条线程内部发生的checked异常,必须也只能在内部用try-catch处理掉,不能往外抛,因为 ...

  5. Java学习笔记 --- 多线程

    一.线程相关概念 程序 程序是为完成特定任务,用某种语言编写的一组指令的集合.简单的说就是我们写的代码 进程 1.进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存 ...

  6. Java学习笔记---多线程同步的五种方法

    一.引言 前几天面试,被大师虐残了,好多基础知识必须得重新拿起来啊.闲话不多说,进入正题. 二.为什么要线程同步 因为当我们有多个线程要同时访问一个变量或对象时,如果这些线程中既有读又有写操作时,就会 ...

  7. java学习笔记 --- 多线程(多线程的控制)

    1.线程休眠    public static void sleep(long millis) public class ThreadSleep extends Thread {@Overridepu ...

  8. Java学习笔记(7)——Java基础之IO多线程网络思维导图

    Java面向对象学习笔记之:包括IO(字节流,字符流,节点流,处理流).线程(线程创建,线程控制,线程同步).网络(TCP Scoket,  UDP Scoket)(全屏观看Java学习笔记(7)-- ...

  9. Java学习笔记5-1——多线程

    目录 前言 核心概念 线程创建 继承Thread类 实现Runnable接口 上述两个方法小结 实现Callable接口 并发问题简介 静态代理模式 线程状态 线程停止(stop) 线程休眠(slee ...

  10. java学习笔记14--多线程编程基础1

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note14.html,转载请注明源地址. 多线程编程基础 多进程 一个独立程序的每一次运行称为 ...

最新文章

  1. Centos7上yum安装redis
  2. Java基础学习总结(16)——Java制作证书的工具keytool用法总结
  3. centos7 php安装
  4. UNICODE转多字节
  5. 检测同心圆_(二)光线如何被眼睛检测到?
  6. P1009 [NOIP1998 普及组] 阶乘之和-2022.02.01(python3实现)
  7. 面向对象编程思想以及强、弱引用总结
  8. 关于高校房产管理系统中主要管理模块都有哪些
  9. 中国数字化城市行业现状调研及前景规划分析报告2022~2028年
  10. PAT 1034 有理数四则运算 python
  11. Docer 在centos中修改默认镜像配置
  12. 【DG】DG日常维护
  13. git 查看提交版本以及回滚到指定的版本
  14. 【LeetCode】5454. 统计全 1 子矩形
  15. excel这几大数据处理技巧,高效率操作技能,今天免费交给你!
  16. miui android 7.1,小米MIUI7.1稳定版固件下载 MIUI7.1稳定版完整刷机包下载
  17. 5、收集资料与绘制原理图库和pcb库
  18. 雷军演讲刷屏,我对项目经理人的发展又有了2点想法……
  19. 智源社区AI周刊:Hinton预测破解大脑机制时间;Gary Marcus批判追捧深度学习风潮;谷歌发布Imagen...
  20. 巨兽雅虎倒下了 雅虎日本为什么还活着?

热门文章

  1. 网上毕业答辩!高校举办研究生学位论文网络预答辩
  2. C++解题报告——Rima(字典树+树形DP)
  3. vue项目与ue交互
  4. 自定义SCOM性能视图
  5. 为了相同的前缀-鸭梨山大
  6. 【C++】C++库nlohmann / json的使用
  7. 使用selenium获取京东商品信息
  8. jQuery 基于verify实现验证码 全家桶 一次让你吃饱
  9. Mixly06:国际摩尔斯电码救难信号SOS
  10. 制作一个注册表单页面