day006-多线程
1、 线程概念
a) 什么是主线程
Java程序启动过程中自动创建的并执行main方法的线程称为主线程
- 主线程的执行路径:
从main方法开始到main方法结束
b)什么是子线程
除了主线程的其它所有线程都是子线程。
- 子线程的执行路径:
从run方法到run方法结束
C)线程的运行模式
- 分时式模式:每个线程平均分配CPU使用权,每一个线程使用CPU的时间是相同的。
- 抢占式模式:优先级高的线程抢到CPU的概率高,如果优先级都相同,就是随机抢占cpu的使用权
- Java程序的线程运行模式属于抢占式模式
2、 多线程内存图解
三句重要的小结:
每一个线程都会有自己独立的栈空间
进程的堆空间是被该进程的所有线程共享
在同一个线程中,代码是按顺序从上向下执行的。
3、 创建线程的两种方式
3.1创建一个类继承Thread类
重写run方法:将线程任务写在run()方法体内
调用start()方法,开启线程干活
例子:
package com.yangzhihui.level03.test02; import java.util.Random; public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread01 = new MyThread("线程1:");
MyThread myThread02 = new MyThread("线程2:");
myThread01.start();
myThread02.start();
}
} class MyThread extends Thread {
public MyThread(String name) {
super(name);
} @Override
public void run() {
Random random = new Random(); int sum = 0;
for (int i = 0; i < 30; i++) {
int num;
num = random.nextInt(901) + 100;
sum += num;
System.out.println(Thread.currentThread().getName() + num);
} System.out.println("10个100~1000随机数的和是:" + Thread.currentThread().getName() + sum);
}
}
3.2 实现Runnable
- 步骤:
A)创建一个类实现Runnable接口,重写方法:将线程任务相关的代码写在run方法中
B) 创建实现类对象,根据实现类对象创建Thread对象
C) 调用线程对象的start方法开启线程:会在新的路径中执行run方法
- 使用Runnable接口的好处:
屏蔽了Java类单继承的局限性
可以更好的在多线程之间共享数据
将线程和任务进行分离,降低了程序的耦合性
为线程池提供前提条件
- 匿名内部类
什么时候使用匿名内部类创建线程
当任务只需要执行一次时,可以考虑使用匿名内部类
例子:
实现Runnable接口
1.定义一个子任务类,实现Runnable接口;
2.在子任务类中重写run方法,在run方法中打印子线程的名称;
3.定义一个测试类;
4.在main方法中打印主线程的名称;
5.在main方法中创建一个子任务对象;
6.在main方法中创建一个Thread类的对象,并把子任务对象传递给Thread类的构造方法;
7.调用Thread类对象的start方法开启子线程;
package level01.test03; class MyRunnable03 implements Runnable {
@Override
public void run() {
System.out.println("实现接口方式:子线程的名称--" + Thread.currentThread().getName());
}
} package level01.test03; public class TestMain {
public static void main(String[] args) {
//打印主线程的名称
System.out.println(Thread.currentThread().getName()); //通过Runnable接口实现类对象,开启多线程
MyRunnable03 myRunnable03 = new MyRunnable03();
new Thread(myRunnable03, "线程2").start();
}
}
4、 线程安全
4.1 概念
指两个或两个以上的线程在同时操作一个共享资源时仍然得到正确的结果则就是线程安全。
- 线程安全的案例
火车站买票案例
4.2实现线程安全的方式
4.2.1:同步代码块
同步:每一个线程按顺序执行
异步:可以同时执行(多线程的代名词)
同步代码块格式:
Synchronized(锁对象){
//操作共享资源的代码
}
同步代码块的原理:
能够保证同一时间只有一个对象操作共享资源的代码
锁对象注意事项:
锁对象可以使任意类型的对象。
所有线程必须共用一把锁
例子:
1. 有100个限量版的水杯,但是只能通过实体店和官网才能进行购买,并且分别统计卖了多少。请用线程进行模
拟并设置线程名称用来代表售出途径,再将信息打印出来。
比如(实体店卖出第1个,总共剩余n个..)
package level01.test06; public class Cup implements Runnable{
private int sellNum = 0;
private final int NUM = 100;
private String cupLock = "lock";
@Override
public void run() {
while(true){
synchronized (cupLock){
if(sellNum < NUM){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "卖出第" + (++sellNum) +
"个,总共剩余" + (NUM - sellNum));
}else {
System.out.println(Thread.currentThread().getName() + "买完了");
break;
}
}
}
}
} package level01.test06; public class TestMain {
public static void main(String[] args) {
Cup cup = new Cup(); new Thread(cup, "实体店").start();
new Thread(cup, "官网").start();
}
}
4.2.2 同步方法
同步方法格式:
修饰符 synchronized
返回值类型 方法名(参数列表){…}
同步方法:
能够保证同一时间,只有一个线程执行方法体内的代码
同步方法的注意事项
- 静态同步方法锁对象是:类名.class
附录:每一个类都会有一个Class对象,而且是唯一的。
Class c1 = TicketThread.class;
Class c2 = TicketThread.class;
- 非静态同步方法锁对象是:this
- 静态方法和非静态方法的选择
当方法体内部需要访问到任何非静态成员时,可以定义为静态方法。否则定义为非静态方法。
例子:
1. 有一辆班车除司机外只能承载80个人,假设前中后三个车门都能上车,如果坐满则不能再上车。请用线程模
拟上车过程并且在控制台打印出是从哪个车门上车以及剩下的座位数。
比如:(前门上车---还剩N个座...)
package level01.test07; public class Bus implements Runnable {
private final int NUM = 80;
private int seatNum = 0; @Override
public void run() {
while(seatNum < NUM){
aboardBus();
}
System.out.println("车座已满");
} public synchronized void aboardBus(){
if(seatNum < NUM){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
seatNum++;
System.out.println("从" + Thread.currentThread().getName() +
"上车,剩下" + (NUM - seatNum) + "座位");
}
}
} package level01.test07; import java.io.BufferedWriter; public class TestMain {
public static void main(String[] args) {
Bus bus = new Bus(); new Thread(bus, "前门").start();
new Thread(bus, "中门").start();
new Thread(bus, "后门").start();
}
}
4.2.3 锁
Lock接口:提供了比synchronized代码块和synchronized方法更广泛的锁操作,同步代码块/同步方法具有的功能Lock都有,除了之外更强大,更体现面向对象。
- 常用方法:
lock():上锁
unlock():释放锁
- Lock使用注意事项
lock()和unlock()必须成对出现。一定要 注意在线程执行完共享代码后,要释放锁。
例子:
写一个卖票的程序,
1. 写一个类,该类继承Thread,定义一个变量记录总票数。
2. 开启四个卖票窗口(开始四个线程),同时执行卖票的程序。
要求每卖一张票在控制台输出:当前窗口为:窗口a卖了一张票,剩余票数为19。其中窗口a为线程的名字。
package level01.test08; import java.util.concurrent.locks.ReentrantLock; public class Ticket implements Runnable{
private final int NUM = 20;
private int seatNum = 0;
private ReentrantLock seatLock = new ReentrantLock(); @Override
public void run() {
while(seatNum < 20){
seatLock.lock(); try {
if(seatNum < NUM){
Thread.sleep(100);
seatNum++;
System.out.println("当前窗口:" + Thread.currentThread().getName() +
"卖了一张牌,剩余票数为" + (NUM - seatNum));
}else {
System.out.println(Thread.currentThread().getName() + "票卖完了");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
seatLock.unlock();
}
}
}
} package level01.test08; public class TestMain {
public static void main(String[] args) {
Ticket ticket = new Ticket();
new Thread(ticket,"线程1:").start();
new Thread(ticket,"线程2:").start();
new Thread(ticket,"线程3:").start();
new Thread(ticket,"线程4:").start();
}
}
5、 线程状态
NEW(新建):新建状态,刚刚创建出来,还没有调用start方法
Runnable(可运行):可运行状态,有资格运行,可能正在运行中,也可以不是正在运行
Blocked(锁阻塞):等待其他线程释放锁对象
Wating(无限等待):无限等待
TimedWating(计时等待):限时等待,调用了sleep方法或者wait(毫秒数),需要被其他线程调用notify方法唤醒
Teminated(被终止):死亡状态,任务执行完毕或调用了stop方法
day006-多线程的更多相关文章
- Python中的多进程与多线程(一)
一.背景 最近在Azkaban的测试工作中,需要在测试环境下模拟线上的调度场景进行稳定性测试.故而重操python旧业,通过python编写脚本来构造类似线上的调度场景.在脚本编写过程中,碰到这样一个 ...
- 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例
前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...
- 多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类)
前言:刚学习了一段机器学习,最近需要重构一个java项目,又赶过来看java.大多是线程代码,没办法,那时候总觉得多线程是个很难的部分很少用到,所以一直没下决定去啃,那些年留下的坑,总是得自己跳进去填 ...
- Java多线程
一:进程与线程 概述:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进程运行时,内部可能包括多个顺序执行流,每个顺序执行流就是一个线程. 进程:进程 ...
- .NET基础拾遗(5)多线程开发基础
Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...
- Java多线程基础——对象及变量并发访问
在开发多线程程序时,如果每个多线程处理的事情都不一样,每个线程都互不相关,这样开发的过程就非常轻松.但是很多时候,多线程程序是需要同时访问同一个对象,或者变量的.这样,一个对象同时被多个线程访问,会出 ...
- C#多线程之线程池篇3
在上一篇C#多线程之线程池篇2中,我们主要学习了线程池和并行度以及如何实现取消选项的相关知识.在这一篇中,我们主要学习如何使用等待句柄和超时.使用计时器和使用BackgroundWorker组件的相关 ...
- C#多线程之线程池篇2
在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...
- C#多线程之线程池篇1
在C#多线程之线程池篇中,我们将学习多线程访问共享资源的一些通用的技术,我们将学习到以下知识点: 在线程池中调用委托 在线程池中执行异步操作 线程池和并行度 实现取消选项 使用等待句柄和超时 使用计时 ...
- C#多线程之线程同步篇3
在上一篇C#多线程之线程同步篇2中,我们主要学习了AutoResetEvent构造.ManualResetEventSlim构造和CountdownEvent构造,在这一篇中,我们将学习Barrier ...
随机推荐
- 挑战程序设计竞赛 P131 区间DP
书上好多题没补 PS.整个DP是根据Q来划分的,dalao的代码就是不一样啊 #include<bits/stdc++.h> #define rep(i,j,k) for(int i=j; ...
- PIE SDK打开HDF、NC数据
1. 功能简介 HDF 是美国国家高级计算应用中心(National Center for Supercomputing Application)为了满足各种领域研究需求而研制的一种能高效存储和分发科 ...
- 转 .net 获取IP地址的三个方法的比较
获取用户IP地址的三个属性的区别(HTTP_X_FORWARDED_FOR,HTTP_VIA,REMOTE_ADDR) 一.没有使用代理服务器的情况: REMOTE_ADDR = 您的 IP ...
- vm12下Centos6的javaweb环境搭建
配置linux的javaweb环境之前: 1.在windows安装xshell(非必需,但是推荐) 2.在linux安装Linux与windows文件传输工具RZSZ[root@192 ~]# yum ...
- SQL Server Reporting Service(SSRS) 第七篇 常见错误汇总
1. The current action cannot be completed. The user data source credentials do not meet the requirem ...
- Oracle 更改归档文件到ASM磁盘
01,配置磁盘路径
- Oracle RAC集群搭建(一)-ASM共享存储卷
01, ASM共享存储卷 安装集群的话,必须要有共享磁盘,目的是为作裁决磁盘使用.还需要有数据文件的共享磁盘 02,规划 主机 裁决磁盘 数据 rac1 1G*1 20 ...
- Java基础21-构造函数之间的调用
public class Test{ public static void main(String[] args){ Persion p2=new Persion("小明",22) ...
- (转)模块readline解析
模块readline解析 原文:https://www.cnblogs.com/fireflow/p/4841413.html readline模块定义了一系列函数用来读写Python解释器中历史命令 ...
- mysql存储过程嵌套循环并分页处理数据
业务背景:公司存证产品升级,随着数据量的增加,存证产品线按业务分表,导致以往的存证关联数据需要做数据同步更新.版本发布前,通过当前存储过程解决数据升级问题. ##创建存证文档关联情况下更新所用存储过程 ...