多线程学习笔记

线程简介 为什么要有线程

用一只手做事情显然是效率比较低的 ,两只手,再来一个人 合作去完成某一件事情显然就会效率高了。

就是在程序执行中 出现了 供需不平衡

为了使程序更快,更高,更强,所以需要多线程。多个线程操作一个资源的时候,会出现混乱,就需要让线程对资源的操作有序,就需要用到锁,同步。

程序 线程 进程

在操作系统中运行的一些程序,这些程序就是进程, 一个进程可以有多个线程,比如 QQ,微信。可以和多个人一起聊天,B站看视频,又可以播放视频,同时发弹幕,就是多个线程

线程实现方法

  1. 继承 Thread类

    public class TestThread extends  Thread{//重写run方法@Overridepublic void run() {//方法体、for (int i = 0; i <20 ; i++) {System.out.println("我是run方法" + i);}}public static void main(String[] args) {//创建线程对象  调用startTestThread testThread = new TestThread();testThread.start();//主线程for (int i = 0; i <20 ; i++) {System.out.println("我是main方法" + i);}}
    }
    // 执行结果如下
    我是main方法6
    我是main方法7
    我是run方法0
    我是run方法1
    我是main方法8
    我是main方法9
    我是main方法10
    我是run方法2//  多条执行路径,交替执行  cpu 调度线程
    
  2. 实现Runable接口

public class TestThread  implements   Runnable{//重写run方法@Overridepublic void run() {//方法体、for (int i = 0; i <20 ; i++) {System.out.println("我是run方法" + i);}}public static void main(String[] args) {//创建线程对象  调用startTestThread testThread = new TestThread();
//        testThread.run();  这样调用也可以执行方法,本质上是顺序执行。new Thread(testThread).start();}
}//多线程就是分时利用CPU,宏观上让所有线程一起执行 ,也叫并发
// 发现问题  实现接口之后 直接创建对象调用run方法也可以执行 是为什么//结果: 可以运行  但是run() 方法调用还是顺序执行, 调用start() 是线程进入jvm虚拟机调度。这才是多线程执行真正的目的。
推荐实现接口 Runable 因为继承只能单继承,局限性。
  1. 实现Callable接口(可以有返回值)
package hy.test;import java.util.concurrent.*;//买票方法
public class TestCallable  implements Callable {//重写call方法有返回值@Overridepublic Boolean call() {System.out.println(Thread.currentThread().getName() + "执行了call方法");return true;}public static void main(String[] args) throws ExecutionException, InterruptedException {//        实现callable 接口 调用线程的步骤TestCallable t1 = new TestCallable();TestCallable t2 = new TestCallable();//1 创建执行服务 创建线程池ExecutorService service = Executors.newFixedThreadPool(2);//2 提交结果Future r1 = service.submit(t1);Future r2 = service.submit(t1);//3 获取结果boolean b1 = (boolean) r1.get();boolean b2 = (boolean) r2.get();System.out.println("b1 = " + b1);System.out.println("b2 = " + b2);//4 关闭服务service.shutdown();}}// 结论 使用callable 接口需要将线程对象提交到线程池中执行,call方法可以有返回值,可以有抛出异常。
  1. 线程池 Executors工具类可以创建三种线程

并发问题

多个线程(对象) 对同一个资源进行操作、

线程的状态

  • 创建状态

    • 线程一旦创建
  • 就绪状态
    • 调用start() 进入就绪状态
  • 运行状态
    • 这个状态就是执行run()方法中的代码
  • 阻塞状态
    • 当调用 sleep() , wait() , yield() 线程就会进入阻塞状态,阻塞状态解除之后,线程会重新进入就绪状态等待CPU调度
  • 死亡状态
    • 线程中断或者结束,一旦进入死亡状态,就不能再次启动。
方法 说明
setPriority() 更改线程的优先级
static void sleep (long millis) 在设置的时间内让该线程休眠
void join() 等待该线程终止
static void yield() 暂停当前线程,执行其他线程(礼让,不一定会成功)
void interrupt() 中断线程 不推荐使用
boolean inAlive() 测试线程是否处于活动状态

让线程停止

推荐使用一个标志位来控制。

// 使用标志位 停止线程
public class TestThread  implements Runnable {private boolean flag = true;@Overridepublic void run() {int i = 0;while(flag){System.out.println("run线程执行中" + i++);}}public void  stop(){this.flag = false;}public static void main(String[] args) {TestCallable t = new TestCallable();new Thread(t).start();for (int i = 0; i < 100; i++) {if(i == 90){t.stop();System.out.println("run线程停止了");}System.out.println("main线程执行" + i);}}
}

线程休眠 sleep

休眠不会释放锁

守护线程(daemon)

  • 线程分为用户线程和守护线程
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不用邓艾守护线程执行完毕
  • 如 后台记录操作日志,监控内存,垃圾回收等待。。。
  • 守护线程结束就是程序运行结束之后
Tread thread = new Thread(xxx)
thread.setDaemon(true)

线程同步

同一个资源被多个线程操作—并发。

线程同步就是排队。

(synchronized): 拿到锁才可以操作资源。

每个线程都有自己的工作内存,所以会有数据不同步的线程,数据不可见。

Synchonized 关键字 锁对象或者锁模板类Class

这是个关键字,两种用法 synchronized方法 和 synchronized 代码块。 影响性能,,,

  • 用法1 关键字synchronized

//买票的安全问解决
public class TestTickets implements Runnable {private boolean flag = true;private int tickets = 10;@Overridepublic void run() {while(flag){try {buy();} catch (InterruptedException e) {e.printStackTrace();}}}//同步方法 锁 thispublic  synchronized void  buy() throws InterruptedException {//买票if(tickets<=0){flag = false;return;}Thread.sleep(100);System.out.println(Thread.currentThread().getName()+"拿到票"+ tickets--);}public static void main(String[] args) {TestTickets t1 = new TestTickets();new Thread(t1,"小明").start();new Thread(t1,"小红").start();new Thread(t1,"张三").start();}
}

用法二 同步块

synchronized(obj){//代码块//obj 是同步监视器  可以是任何对象,但是推荐使用共享资源作为同步监视器//同步方法中无需指定同步监视器,因为同步方法的同步监视器就是把this,就是这个方法本身,或者Class
}

死锁

两个线程持有对方想获取的锁,都拿不到锁,僵持了、、、

//买票方法
public class MakeUp extends Thread {int choice;String name;static Mirror mirror = new Mirror(); //static 保证只有1份资源static Lipstick lipstick = new Lipstick();MakeUp(int choice,String name){this.choice = choice;this.name = name;}@Overridepublic void run() {try {makeUp();} catch (InterruptedException e) {e.printStackTrace();}}public  synchronized void  makeUp() throws InterruptedException {if(choice == 0){synchronized (lipstick){System.out.println(this.name + "获得口红锁");Thread.sleep(1000);synchronized(mirror){System.out.println(this.name + "获得镜子锁");}}}else{synchronized (mirror){System.out.println(this.name + "获得口红锁");Thread.sleep(2000);synchronized(lipstick){System.out.println(this.name + "获得镜子锁");}}}}public static void main(String[] args) {MakeUp t1 = new MakeUp(0,"小红");MakeUp t2 = new MakeUp(1,"小张");t1.start();t2.start();}
}
//镜子
class Mirror{}//口红
class Lipstick{}
  • 互斥 条件 一个资源一次只能被一个进程使用’
  • 请求与保持条件: 一个人手里拿着西瓜排队打饭,队伍太长,等太久,手里的西瓜别人想要而他不放手
  • 不剥夺条件: 一个人正在上厕所,还没上完,其他人只能等着
  • 循环等待条件: A要B的东西 B要A的东西 僵持了

Lock JDK5.0+

更细颗粒度的锁

ReentrantLock 可重入锁

 Lock l = ...;
l.lock();
try { // access the resource protected by this lock
} finally {l.unlock();
}
  • 怎么使用
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class LockTest implements Runnable{private int tickets = 10;//定义可重入锁Lock lock = new ReentrantLock();@Overridepublic void run() {while(true){try {lock.lock(); //加锁if(tickets <=0){break;}try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() +"=====" + tickets--);} finally {lock.unlock();}}}public static void main(String[] args) {LockTest lockTest = new LockTest();new Thread(lockTest).start();new Thread(lockTest).start();new Thread(lockTest).start();}
}

线程通信

线程之间进行交流。生产者消费者模式。 管程法

package hy.test;//生产者消费者模型  生产者  消费者  缓冲区 产品
public class  LockTest{public static void main(String[] args) {SynContainer synContainer = new SynContainer();Produce produce = new Produce(synContainer);Consumer consumer = new Consumer(synContainer);produce.start();consumer.start();}
}//生产者
class Produce extends  Thread{SynContainer container;public Produce(SynContainer container){this.container = container;}//生产者生产产品@Overridepublic void run() {for (int i = 0; i < 100; i++) {container.push(new Product(i));System.out.println("生产了"+ i + "个产品");}}
}//消费者
class  Consumer extends Thread{SynContainer container;public Consumer(SynContainer container){this.container = container;}//消费者消费产品@Overridepublic void run() {for (int i = 0; i < 100; i++) {container.pop();System.out.println("消费了"+ i + "个产品");}}
}//产品
class Product{private int id;public Product(int id){this.id = id;}}
//缓冲区
class SynContainer{//一个容器 存放产品Product[] arr = new Product[10];int count = 0;//生产者存放产品public synchronized void push(Product product){//如果容器满了就等待消费者取走产品if(count == arr.length){//通知消费者消费try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果容器没有满,就存放进去arr[count] = product;count++;//可以通知消费者消费了this.notifyAll();}//消费者获取产品public synchronized Product pop(){//判断是否有产品 如果没有等待生产if(count == 0 ){try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//消费者消费。。//如果有产品就消费count--;Product product = arr[count];this.notifyAll();return product;}
}

线程池

使用Executors工具类创建 不推荐

package hy.test;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class TestPool {public static void main(String[] args) {//创建一个指定数量的线程池
//        ExecutorService pool = Executors.newFixedThreadPool(3);//创建一个线程池
//        ExecutorService pool = Executors.newSingleThreadExecutor();//创建可变线程池ExecutorService pool = Executors.newCachedThreadPool();//        pool.execute(new MyThread());
//        pool.execute(new MyThread());
//        pool.execute(new MyThread());pool.submit(new MyThread());pool.submit(new MyThread());pool.submit(new MyThread());pool.submit(new MyThread());//关闭连接pool.shutdown();}}class MyThread implements  Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName() +"====== ");}
}

使用 ThreadPoolExecutor 自定义创建线程池

ThreadPoolExecutor(int corePoolSize,  //核心线程数 就是日常备战的int maximumPoolSize, // 设置最大线程数量 long keepAliveTime,  //设置活跃时长 一定时间之后大于核心线程数的线程会去休息TimeUnit unit, //设置时间单位BlockingQueue<Runnable> workQueue, //设置阻塞队列。可执行任务数量 就是能有多少人在那排队等待线程执行// 这个队列将仅保存execute方法提交的Runnable任务ThreadFactory threadFactory, //线程创建工厂RejectedExecutionHandler handler) //拒绝策略,就是线程池满了之后无法接受新的任务
创建一个新 ThreadPoolExecutor给定的初始参数。

JUC 并发包

多线程学习笔记20210121相关推荐

  1. java 多线程语法_Java基础语法之多线程学习笔记整理

    众所周知,利用好多线程机制,可以大大提高系统整体的并发能力以及性能,而且线程间的切换和调度的成本小.因此,多线程是Java学习者必须掌握的语法重点.本文为大家整理了进程和线程.实现多线程方式.设置和获 ...

  2. java线程集合点_Java多线程学习笔记(三) 甚欢篇

    使人有乍交之欢,不若使其无久处之厌 <小窗幽记>很多时候,我们需要的都不是再多一个线程,我们需要的线程是许多个,我们需要让他们配合.同时我们还有一个愿望就是复用线程,就是将线程当做一个工人 ...

  3. java多线程学习笔记。

    java多线程学习笔记 线程的优缺点: 多线程的好处: 充分利用多处理核心,提高资源的利用率和吞吐量. 提高接口的响应效率,异步系统工作. 线程的风险: 安全危险(竞争条件):什么坏事都没有发生.在没 ...

  4. java 编程思想 多线程学习笔记

    java 编程思想 多线程学习笔记 一.如何创建多线程? 1.继承 java.lang.Thread 类 2.实现 java.lang.Runnable 接口 3.Callable接口 总之,在任何线 ...

  5. Java之多线程学习笔记五 —— 多线程模拟龟兔赛跑

    Java之多线程学习笔记五 -- 多线程模拟龟兔赛跑 参考教程B站狂神https://www.bilibili.com/video/BV1V4411p7EF package pers.ylw.less ...

  6. oracle数据库开多线程,学习笔记:Oracle表数据导入 DBA常用单线程插入 多线程插入 sql loader三种表数据导入案例...

    天萃荷净 oracle之数据导入,汇总开发DBA在向表中导入大量数据的案例,如:单线程向数据库中插入数据,多线程向数据表中插入数据,使用sql loader数据表中导入数据案例 1.Oracle数据库 ...

  7. java中线程总结_java中多线程学习笔记总结

    线程的简单学习笔记: 1.进程与线程的概念 进程:从用户角度看进程是应用程序的一个执行过程. 从操作系统核心角度看进程代表的是操作系统分配的内存和CPU时间片等资源的基本单位,是为正在运行的程序提供的 ...

  8. Java 多线程学习笔记

    概念 进程 正在运行的程序,是系统进行资源分配和调用的独立单位 每一个进程都有它自己的内存空间和系统资源,一个进程包括由操作系统分配的内存空间,包含一个或多个线程 一个进程一直运行,直到所有的非守护线 ...

  9. Java 多线程学习笔记(狂神)

    学习视频参考链接:https://www.bilibili.com/video/BV1V4411p7EF?p=27 线程简介 线程的实现(重点) 线程状态 线程同步(重点) 线程通信问题 高级主题(重 ...

最新文章

  1. linux怎样标识空设备,Linux系统命令------Ubuntu下解决adb设备列表为空
  2. Visual Studio各个版本对应关系
  3. 每日一练(8)—— 野指针
  4. 代号“凤凰”,阿里新零售秘密武器,今年要打入100个城市
  5. js提交出现post错误_阿里云的 Node.js 稳定性实践
  6. POJ1521 LA2088 HDU1053 ZOJ1117 Entropy【哈夫曼编码】
  7. nginx/windows: nginx多虚拟主机配置
  8. html编写注册页面
  9. Chrome安装插件Hackbar
  10. 无缘晶振匹配电容计算方法
  11. 萝卜小铺与店主的故事(十一)
  12. 哈工大深圳计算机实验室介绍,实验室介绍
  13. 塞班(Symbian)开源了(包括Symbian 3和S60等)
  14. clickhouse开窗函数之同比环比
  15. GNN理论入门和小实践——从卷积讲起
  16. 独立开发变现周刊(第66期): 如何把一个短链接生成工具变成一个可持续盈利的产品?...
  17. SPSS中,进行两独立样本T检验
  18. 20200724-Java-抽象类、接口
  19. android bitmap nv21,Android开发之虹软人脸识别活体检测SDK包Bitmap转NV21方法
  20. kotlin——观察者模式

热门文章

  1. Linux 进程间通信-IPC 机制
  2. 【生成对抗网络 论文泛读】……pix2pix pix2pixhd……
  3. MySQL数据库——语句
  4. spring bean的init、destory的几种方法及生命周期
  5. Linux 配置git同步GitHub代码
  6. 【已解决】部分安卓手机,部分ios机型,调微信的jssdk方法失败
  7. Vue关于pdf展示问题——第三方电子签章不能正常展示
  8. UVA - 1600 Patrol Robot (巡逻机器人)(bfs)
  9. 程序员分前端与后端,那么后端程序员都做些什么?看完你就明白了!
  10. PHP互联网工长装修O2O服务平台源码