Java基础篇---多线程
内容导航:
第一部分多线程的实现方式
在java中多线程实现方式有2种
一、自定义一个类A,继承Thread类
public class ThreadA extends Thread {
public void run(){
}
}
}
此时ThreadA是一个线程类,在ThreadA中重写Thread类中的run方法
调用方式如下
ThreadA A = new ThreadA();
A.start();
二、自定义一个类B,实现Runable接口
public class ThreadB implements Runnable {
public void run() {
}
}
此时ThreadB不是一个线程类,在ThreadB中重写Thread类中的run方法
ThreadB b = new ThreadB();
Thread t1 = new Thread(b);
t1.start();
需要在初始化Thread的时候,把Runnable接口的实现类的对象b作为参数传入
第二部分是线程安全问题
线程安全问题产生的场景:
public class SaleTickets implements Runnable {
private int num = 100; //表示100张火车票 这是共享资源
//买100张火车票
public void run() {
for (int i = 0; i < num; i++) {
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "买了编号为" + num + "的火车票");
num--;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
}
}
SaleTickets st=new SaleTickets ();
Thread tA=new Thread(st); //用户A
Thread tB=new Thread(st); //用户B tA.setName("用户A线程");
tB.setName("用户B线程"); tA.start();
tB.start();
进入12306购买火车票的时候,为了解决多个人同时进行抢票问题,需要使用多线程来增加系统效率,假如票共有100张,用户A和用户B同时进行买票,如果是单线程,每次用户买票的时候,首先会打印用户买到了哪张票,然后票的总数num减1。
但是由于是多线程,多线程有一个特性就是线程的执行顺序由cpu来分配,所以执行顺序是不确定的,假如用户A执行SaleTickets方法中的第10行的时候,会打印出用户A线程买了编号为100的火车票,此时用户B线程也开始执行SaleTickets方法,用户B也会打印出用户B线程买了编号为100的火车票
这种结果不是合理的,所以就引发线程安全问题
解决线程安全问题的方式有2种
1、同步代码块
public class SaleTickets implements Runnable {
private int num = 100; //表示100张火车票 这是共享资源
//买100张火车票
public void run() {
for (int i = 0; i < num; i++) {
synchronized (this){
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "买了编号为" + num + "的火车票");
num--;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
}
}
}
2、同步方法
public class SaleTickets implements Runnable {
private int num = 100; //表示100张火车票 这是共享资源
public synchronized void saleOne(){
if (num > 0) {
System.out.println(Thread.currentThread().getName() + "买了编号为" + num + "的火车票");
num--;
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
}
}
//买100张火车票
public void run() {
for (int i = 0; i < 10; i++) {
saleOne();
}
}
}
此时同步方法中的synchronized的锁默认为this
第三部分是线程间通信
线程间的通信机制为等待唤醒机制,多个线程通信的前提是共用同一把锁
wait(long timeout) 当前线程释放锁,并等待timeout毫秒
notify 唤醒持有同一锁的某个线程
1、定义一个静态object对象,作为线程间通信的锁
public class MyLock {
public static Object obj = new Object();
}
2、定义线程A
//定义一个线程类 输出1
public class ThreadA extends Thread { public void run(){
for(int j=0;j<10;j++){
synchronized (MyLock.obj) {
System.out.println(1);
MyLock.obj.notify();
try {
MyLock.obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} }
3、定义线程B
//定义一个线程类 输出2
public class ThreadB extends Thread { public void run(){
for(int j=0;j<10;j++){
synchronized (MyLock.obj) {
System.out.println(2);
MyLock.obj.notify();
try {
MyLock.obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} }
4、定义主函数执行线程A和线程B
public class TestThreadForSignal {
public static void main(String[] args){
new ThreadA().start();
new ThreadB().start();
}
}
执行结果:交替打印1和2
执行原理:先执行线程A,会被同步代码块synchronized锁住,打印1,然后唤醒共用MyLock.obj锁的线程B,然后线程A进入等待,并释放锁。然后执行线程B,会被同步代码块synchronized锁住,打印2,然后唤醒共用MyLock.obj锁的线程A,然后线程B进入等待,并释放锁。接下来继续执行线程A循环往复.......
第四部分是生产者消费者模式
利用线程间通信可以很好的实现生产者消费者模式
因为这个代码跟上面线程通信的代码很类似,这里博主不打算继续码代码了,用文字做一个简要说明
线程A (农夫) 往篮子里放苹果 如果篮子满了(苹果数量=10),线程A wait,如果没满(苹果数量<10),往篮子里放苹果,同时告诉B(小孩儿) notify唤醒
线程B (小孩儿)从篮子里拿苹果吃 如果篮子空了(苹果数量=0),线程B wait 如果篮子里还有苹果(苹果数量>0),从篮子里拿苹果吃 同时告诉A(农夫)notify唤醒
在这个场景里线程A(农夫)是生产者,线程B(小孩儿)是消费者
Java基础篇---多线程的更多相关文章
- 金三银四跳槽季,BAT美团滴滴java面试大纲(带答案版)之一:Java基础篇
Java基础篇: 题记:本系列文章,会尽量模拟面试现场对话情景, 用口语而非书面语 ,采用问答形式来展现.另外每一个问题都附上“延伸”,这部分内容是帮助小伙伴们更深的理解一些底层细节的补充,在面试中可 ...
- 小白—职场之Java基础篇
java基础篇 java基础 目录 1.java是一种什么语言,jdk,jre,jvm三者的区别 2.java 1.5之后的三大版本 3.java跨平台及其原理 4.java 语言的特点 5.什么是字 ...
- java基础篇---I/O技术
java基础篇---I/O技术 对于任何程序设计语言而言,输入输出(I/O)系统都是比较复杂的而且还是比较核心的.在java.io.包中提供了相关的API. java中流的概念划分 流的方向: 输 ...
- java基础篇---HTTP协议
java基础篇---HTTP协议 HTTP协议一直是自己的薄弱点,也没抽太多时间去看这方面的内容,今天兴致来了就在网上搜了下关于http协议,发现有园友写了一篇非常好的博文,博文地址:(http: ...
- java基础篇---I/O技术(三)
接上一篇java基础篇---I/O技术(二) Java对象的序列化和反序列化 什么叫对象的序列化和反序列化 要想完成对象的输入或输出,还必须依靠对象输出流(ObjectOutputStream)和对象 ...
- Java基础篇 - 强引用、弱引用、软引用和虚引用
Java基础篇 - 强引用.弱引用.软引用和虚引用 原创零壹技术栈 最后发布于2018-09-09 08:58:21 阅读数 4936 收藏展开前言Java执行GC判断对象是否存活有两种方式其中一种是 ...
- java基础篇 之 构造器内部的多态行为
java基础篇 之 构造器内部的多态行为 我们来看下下面这段代码: public class Main { public static void main(String[] args) { new ...
- java基础篇1
JAVA基础篇1 注释 单行注释 //这是一个单行注释,由两个斜杠组成,不能嵌套多行注释 多行注释 /*这是一个 多行注释 ,//里面不能嵌套多行注释, 但是可以嵌套单行注释*/ 文档注释 /**ja ...
- Java基础篇(JVM)——类加载机制
这是Java基础篇(JVM)的第二篇文章,紧接着上一篇字节码详解,这篇我们来详解Java的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...
随机推荐
- Lavevel 中 trait 如何继承与复写
1 写一个基类 2 基类中 use YourTrait 3 写一个子类 extends 基类 4 子类中覆写 YourTrait 中的同名方法 $query = parent::scopeOfPara ...
- Java+web+上传文件夹
用JAVA实现大文件上传及显示进度信息 ---解析HTTP MultiPart协议 (本文提供全部源码下载,请访问 https://github.com/1269085759/up6-jsp-mysq ...
- bzoj 1924
所用点的编号为输入顺序,因为只有在存在联通门的宫室中存在宝藏.其余点不考虑 对于每一行,选定一个横天门,向该行横天门连双向边,其余门单向边纵列同理自.由门用map判周围八个点是否存在,存在即连边 Ta ...
- 8月清北学堂培训 Day1
今天是赵和旭老师的讲授~ 动态规划 动态规划的基本思想 利用最优化原理把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解. 更具体的,假设我们可以计算出小问题的最优解,那么我们凭借此可 ...
- tarjan缩点——在农场万圣节Trick or Treat on the Farm
一个房间能到另一个房间,有向图,奶牛从自己编号(1到n)的点出发,如果回到以前到过的点就停止,问每头奶牛可以经过几个点: 情况分两种, 一,奶牛在环上,能走的是环的大小,二,一条链连接一个环,大小是链 ...
- XXE外部实体注入漏洞——PHP
前言 XXE Injection即XML External Entity Injection,也就是XML外部实体注入攻击.漏洞是在对非安全的外部实体数据进行处理时引发的安全问题. 在XML1.0标准 ...
- 2019balsn两道web和2019巅峰极客一道web记录
遇到3道有点意思的web,记录一下~ web1 题目地址:http://warmup.balsnctf.com/ 源码如下所示: <?php if (($secret = base64_deco ...
- 20175313 张黎仙《Java程序设计》第十一周学习总结
目录 一.教材学习内容总结 二.教材学习中的问题和解决过程 三.代码托管 四.心得体会 五.学习进度条 六.参考资料 一.教材学习内容总结 第十三章内容 主要内容 URL类 InetAdress类 套 ...
- Linux设备驱动程序 之 中断
中断 中断使得硬件可以发出通知给处理器,本质上是一种特殊的电信号,由硬件设备发向处理器,处理器接收到中断后,会马上向操作系统反应此信号的到来,然后就由操作系统负责处理这些新来的数据:硬件设备生成中断并 ...
- recyclerView 嵌套 recyclerView 点击被拦截
上层recyclerView.setLayoutFrozen(true);下层可以接收到点击事件.