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的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...
随机推荐
- P4295 [SCOI2003]严格N元树 DP
思路:DP 提交:\(5\)次 错因:2次高精写错(我太菜了),2次写错特判 题解: 设\(f[i]\)表示深度\(\leq i\)的严格\(n\)元树的数目,有 \[f[i]=pow(f[i-1], ...
- Dynamic Data linq to SQL Web Application
微软提供了一个数据驱动网站模板,可以自动生成CRUD页面,使用过程中碰到些问题 1.首先是如何应用,只需要创建个context并且在Global.asax里面加入下面这一句就可以了 DefaultMo ...
- thinkphp5 大量数据批量插入数据库的解决办法
对于数据量很小,怎么玩都是可以的. but!!! 如果有几十万或者百万级别的数据,该怎么处理,请往下面看
- 7月清北学堂培训 Day 4
今天是丁明朔老师的讲授~ 图论 图是种抽象结构,这种抽象结构可以表示点与点之间的关系. 最短路: Dijkstra(堆优化) SPFA Floyd 最小生成树: Kruscal 连通性: BFS / ...
- python pywin32 安装
pip install pywin32 参考: https://blog.csdn.net/qq_38161040/article/details/85075158
- codeforces#1234F. Yet Another Substring Reverse(子集dp)
题目链接: https://codeforces.com/contest/1234/problem/F 题意: 给出一个只包含前20个小写字母的字符串,一次操作可以让一段字符颠倒顺序 最多一次这样的操 ...
- JavaWeb_(Mybatis框架)关联查询_六
系列博文: JavaWeb_(Mybatis框架)JDBC操作数据库和Mybatis框架操作数据库区别_一 传送门 JavaWeb_(Mybatis框架)使用Mybatis对表进行增.删.改.查操作_ ...
- OpenFOAM 中的边界条件(一)【转载】
链接:http://xiaopingqiu.github.io/2016/04/02/Boundary-conditions-in-OpenFOAM1/ 本系列解读 OpenFOAM 中边界条件的实现 ...
- 手游折扣app票选结果公布哪个好哪个靠谱一目了然
2018年,是中国改革开放40年,也是中国互联网20年.“互联网推动了精神文明向更高水平的迈进,实现人的价值第一,创造美好生活,从生产高于生活.艺术高于成活,转向发现与实现生活本身美好,让想象成真.如 ...
- 你真的会用go语言写单例模式吗?
最近在学习Golang,想着可以就以前的知识做一些串通,加上了解到go语言也是面向对象编程语言之后.在最近的开发过程中,我碰到一个问题,要用go语言实现单例模式.本着“天下知识,同根同源”(我瞎掰的~ ...