多线程学习笔记20210121
多线程学习笔记
线程简介 为什么要有线程
用一只手做事情显然是效率比较低的 ,两只手,再来一个人 合作去完成某一件事情显然就会效率高了。
就是在程序执行中 出现了 供需不平衡
了
为了使程序更快,更高,更强,所以需要多线程。多个线程操作一个资源的时候,会出现混乱,就需要让线程对资源的操作有序,就需要用到锁,同步。
程序 线程 进程
在操作系统中运行的一些程序,这些程序就是进程, 一个进程可以有多个线程,比如 QQ,微信。可以和多个人一起聊天,B站看视频,又可以播放视频,同时发弹幕,就是多个线程
线程实现方法
继承 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 调度线程
实现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 因为继承只能单继承,局限性。
- 实现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方法可以有返回值,可以有抛出异常。
- 线程池 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相关推荐
- java 多线程语法_Java基础语法之多线程学习笔记整理
众所周知,利用好多线程机制,可以大大提高系统整体的并发能力以及性能,而且线程间的切换和调度的成本小.因此,多线程是Java学习者必须掌握的语法重点.本文为大家整理了进程和线程.实现多线程方式.设置和获 ...
- java线程集合点_Java多线程学习笔记(三) 甚欢篇
使人有乍交之欢,不若使其无久处之厌 <小窗幽记>很多时候,我们需要的都不是再多一个线程,我们需要的线程是许多个,我们需要让他们配合.同时我们还有一个愿望就是复用线程,就是将线程当做一个工人 ...
- java多线程学习笔记。
java多线程学习笔记 线程的优缺点: 多线程的好处: 充分利用多处理核心,提高资源的利用率和吞吐量. 提高接口的响应效率,异步系统工作. 线程的风险: 安全危险(竞争条件):什么坏事都没有发生.在没 ...
- java 编程思想 多线程学习笔记
java 编程思想 多线程学习笔记 一.如何创建多线程? 1.继承 java.lang.Thread 类 2.实现 java.lang.Runnable 接口 3.Callable接口 总之,在任何线 ...
- Java之多线程学习笔记五 —— 多线程模拟龟兔赛跑
Java之多线程学习笔记五 -- 多线程模拟龟兔赛跑 参考教程B站狂神https://www.bilibili.com/video/BV1V4411p7EF package pers.ylw.less ...
- oracle数据库开多线程,学习笔记:Oracle表数据导入 DBA常用单线程插入 多线程插入 sql loader三种表数据导入案例...
天萃荷净 oracle之数据导入,汇总开发DBA在向表中导入大量数据的案例,如:单线程向数据库中插入数据,多线程向数据表中插入数据,使用sql loader数据表中导入数据案例 1.Oracle数据库 ...
- java中线程总结_java中多线程学习笔记总结
线程的简单学习笔记: 1.进程与线程的概念 进程:从用户角度看进程是应用程序的一个执行过程. 从操作系统核心角度看进程代表的是操作系统分配的内存和CPU时间片等资源的基本单位,是为正在运行的程序提供的 ...
- Java 多线程学习笔记
概念 进程 正在运行的程序,是系统进行资源分配和调用的独立单位 每一个进程都有它自己的内存空间和系统资源,一个进程包括由操作系统分配的内存空间,包含一个或多个线程 一个进程一直运行,直到所有的非守护线 ...
- Java 多线程学习笔记(狂神)
学习视频参考链接:https://www.bilibili.com/video/BV1V4411p7EF?p=27 线程简介 线程的实现(重点) 线程状态 线程同步(重点) 线程通信问题 高级主题(重 ...
最新文章
- linux怎样标识空设备,Linux系统命令------Ubuntu下解决adb设备列表为空
- Visual Studio各个版本对应关系
- 每日一练(8)—— 野指针
- 代号“凤凰”,阿里新零售秘密武器,今年要打入100个城市
- js提交出现post错误_阿里云的 Node.js 稳定性实践
- POJ1521 LA2088 HDU1053 ZOJ1117 Entropy【哈夫曼编码】
- nginx/windows: nginx多虚拟主机配置
- html编写注册页面
- Chrome安装插件Hackbar
- 无缘晶振匹配电容计算方法
- 萝卜小铺与店主的故事(十一)
- 哈工大深圳计算机实验室介绍,实验室介绍
- 塞班(Symbian)开源了(包括Symbian 3和S60等)
- clickhouse开窗函数之同比环比
- GNN理论入门和小实践——从卷积讲起
- 独立开发变现周刊(第66期): 如何把一个短链接生成工具变成一个可持续盈利的产品?...
- SPSS中,进行两独立样本T检验
- 20200724-Java-抽象类、接口
- android bitmap nv21,Android开发之虹软人脸识别活体检测SDK包Bitmap转NV21方法
- kotlin——观察者模式