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的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...
随机推荐
- JQuery实践--插件
jQuery插件的概览http://docs.jquery.com/Pluginshttp://jquery.com/plugins/most_popular 官方的表单插件http://jquery ...
- window、BOM、 document、 DOM
window: 顾名思义,窗口,浏览器窗口.是Window构造函数的一个实例对象. 它包含浏览器的一些属性和方法,如screen,location,history,setInterval等. // ...
- learning express step(九)
router-level middleware works in the same way as application-level middleware, except it is bound to ...
- P3979 遥远的国度 树剖
P3979 遥远的国度 树剖 题面 需要想一下的树剖题,对于询问三需要处理换跟后的情况.我们以1为树根跑一遍剖分,对于换跟进行分类讨论,算出实际答案.讨论有三种情况: (以1为树根的树上) 跟在询问节 ...
- 学院管理系统(mysql版)
需求 用户角色,讲师\学员, 用户登陆后根据角色不同,能做的事情不同,分别如下 讲师视图 管理班级,可创建班级,根据学员qq号把学员加入班级 可创建指定班级的上课纪录,注意一节上课纪录对应多条学员的上 ...
- slax linux的定制
由于数据结构教学的需要,需要用到linux,要求就是小,启动快,可定制性强,恰好slax正好满足要求,以下就是定制slax linux的过程记录: 什么是Slax Slax是一个基于Linux的Liv ...
- JAVA基础知识|反射
一.理解反射 1.1.基础概念 反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象方法的功能称为ja ...
- WebService基础学习
参考 WebService基础学习(一)—基础知识:http://www.cnblogs.com/yangang2013/p/5708647.html WebService基础学习(二)—三要素:ht ...
- 拆分项目搞成framework 实例
目前工作中遇到的问题,是讲项目三大模块拆分, 将Discover.Shop和Events的源代码拆分到独立的项目中 拆分是个麻烦事,里面相互依赖很多 ,打包编译也异常复杂,各种报错 编译Event 遇 ...
- ArcGIS超级工具SPTOOLS-按属性裁剪,矢量数据批量裁剪,矢量数据批量合库
1.1 按属性裁剪 操作视频: https://weibo.com/tv/v/HwaZRoosq?fid=1034:4376687438183117 按属性裁剪:可以图形表,也可以是非图形表,字段值 ...