javasE--基础部分--线程
Day23
本单元目标
一.线程的相关概念
二.线程的创建和启动★
三.线程的停止
四.线程的常用方法
五.线程的生命周期★
六.线程的同步
七.线程的通信
八.线程的创建方式三
九.线程的创建方式四(线程池)
一.线程的相关概念
程序:是完成特定任务、用某种语言编写的一组指令的集合
进程:是程序的一次执行过程,或是正在运行的一个程序
线程:进程可进一步细化为线程,线程是进程中的一个细小的单元
单线程:一个程序,在“同一时刻”只能执行一个线程
多线程:一个程序,在“同一时刻”可以同时执行多个线程
双核
多核
高并发
高频率
二、线程的创建和启动
1、之前的所有代码都是单线程
2、线程的创建方式(两种)一共是四种
2.1 a 新建一个类
b 继承一个类Thread
c 重写run方法(实际运行的代码)
启动线程的方式:
a。 创建一个线程对象
Thread1 t1=new Thread1();
b。调用当前线程的start方法
t1.start();//启动线程的正确方式(实际运行的依然是run方法)
2.2
a 新建一个类
b实现一个接口Runable
c实现接口中的抽象方法 run方法
启动线程的方式
a 创建线程对象
b通过Thread类进行包装
c调用Start方法进行启动
t22.start();//实际运行的依然是t2的run 方法
3、 练习
1 创建两个子线程,让其中一个输出1-100之间的偶数,另一个输出1-100之间的奇数。
package Demo;
//创建两个子线程,让其中一个输出1-100的偶数,另一个输出1-100之间的奇数
public class Demo3 {
public static void main(String[] args) {
Thread1 t1=new Thread1();
t1.start();
Thread2 t2=new Thread2();
Thread t22=new Thread(t2);
t22.start();
}
}
class Thread1 extends Thread{
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 101; i++) {
if (i%2==0) {
System.out.println("偶数"+i);
}
}
super.run();
}
}
class Thread2 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 101; i++) {
if (i%2!=0) {
System.out.println("奇数:"+i);
}
}
}
}
三、线程常见方法
1. 如何停止一个线程
a stop(); 停止一个线程 过时了 不建议使用
b 可以采用逻辑的方式
四.线程的常用方法
currentThread();获得当前线程的对象 静态方法
Thread[Thread-0,5,main] [当前线程的名字,当前线程的优先级,当前线程由哪个线程创建的]
getName();获得线程的名字
setName(String name);设置当前线程的名字
getPriority();获得当前线程的优先级 线程的优先级默认和创建他的线程优先级一致
setPriority(2);设置当前线程的优先级 范围:1-10
sleep(long time);睡眠 设置时间 单位:毫秒 需要抛出一个异常 InterruptedException e
interrupt();中断(不能中断线程) (只是改变了当前线程中一个值的状态)
在中断睡眠或者等待的线程时会抛出一个异常
线程分类
* 守护线程 (负责守护) 当用户线程执行完毕,自己线程无论是否执行完毕都自动结束!
如何设置守护线程 t1.setDaemon(true);//设置为守护线程 需要在启动之前设置
记住守护线程的特点:
java一个最经典的守护线程是 :垃圾回收机制的线程
用户线程 (功能)
2. 练习
编写程序:在main方法中创建一个线程。线程每隔一定时间(200ms以内的随机时间)
2.定义一个接口用来实现两个对象的比较。
interface CompareObject{
public int compareTo(Object o);
//若返回值是 0 , 代表相等; 若为正数,代表当前对象大;负数代表当前对象小
}
定义一个Circle类。
定义一个ComparableCircle类,继承Circle类并且实现CompareObject接口。
在ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的面积大小。
定义一个测试类InterfaceTest,创建两个ComparableCircle对象,
调用compareTo方法比较两个类的半径大小。 产生一个0-100之间的随机整数,打印后将该整数放到集合中;
共产生100个整数,全部产生后,睡眠5秒,然后将集合内容打印输出;
package Demo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*在main方法中创建一个线程。线程每隔一定时间(200ms以内的随机时间)
* 产生一个0-100之间的随机整数,打印后将该整数放到集合中;
共产生100个整数,全部产生后,睡眠5秒,然后将集合内容打印输出;*/
public class Demo4 {
public static void main(String[] args) {
Thread3 t1=new Thread3();
t1.start();
}
}
class Thread3 extends Thread{
List<Integer> list =new ArrayList<Integer>();
@Override
public void run() {
super.run();
// TODO Auto-generated method stub
for (int i = 0; i <100; i++) {
try {
Thread.sleep((long) (Math.random()*200+1));
} catch (Exception e) {
// TODO: handle exception
}
int a = (int)(Math.random()*101);
System.out.println(a);
list.add(a);
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (Integer integer : list) {
System.out.print(integer);
}
五.线程的同步
1、线程的同步
多个窗口买票
1. 互斥锁
a. 为一段代码块上锁
语法:
synchronized(锁对象){//锁对象是任意对象(this或String对象)
需要锁住的代码;关键代码
}
b. 为一段代码块上锁
语法:public synchronized void method(){
//如何让循环结束
}
C.
1.创建一个对象
ReentrantLock lock=new ReentrantLock();
2.在需要被锁住的上一行执行lock方法
lock.lock();
3.在需要被锁住的最后一行下一行执行unlock方法(必须要执行:finally中)
Lock.unlock(); (必须被执行:finally里中)
4. 案例
try {
lock.lock();
if(num<=0){
System.out.println("卖完了");
break;
}
try {
Thread.sleep(400);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"卖出了一张票:剩余:"+--num);
} finally {
lock.unlock();//一定要保证能运行 finally中
}
2、死锁的问题
1、产生原因:
就是锁与锁之间的相互等待
一个线程一直占用这个资源,另一个线程一直在等待他结束
此类用于演示死锁 (避免)
1. 产生的原因:
就是锁与锁之间相互等待
2. 案例见下面代码
public class Demo2 {
public static void main(String[] args) {
Thread1 t1=new Thread1();//新生线程
t1.start();//就绪(可运行)线程
Thread2 t2=new Thread2();
t2.start();
}
}
class Thread1 extends Thread{
@Override
public void run() {
System.out.println("这是Thread1线程");
synchronized ("java") {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread1刚刚睡醒");
synchronized ("html5") {
System.out.println("Thread1内部锁的代码");
}
}
}
}
class Thread2 extends Thread{
@Override
public void run() {
System.out.println("这是Thread2线程");
synchronized ("html5") {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Thread2刚刚睡醒");
synchronized ("java") {
System.out.println("Thread2内部锁的代码");
}
}
}
}
解决懒汉模式
package com.atguigu.demon;
/**
* 此类用于演示解决懒汉模式的线程安全问题
* 1. 代码见下面
*/
public class Demo3 {
}
class Lazy{
private Lazy(){}
private static Lazy lazy;
public static Lazy getLazy(){
if(lazy==null){
synchronized ("aaa") {
if(lazy==null){
lazy=new Lazy();
}
}
}
return lazy;
}
}
六.线程的生命周期★
1、新生线程,(线程对象刚刚诞生)刚new出来
可运行(就绪)线程(调用Start方法)
运行线程 (等待cpu分配执行权)
阻塞线程
睡眠sleep
互斥锁
io阻塞
暂停join
等待wait
死亡线程
以上需要背下来
2、线程的让步和线程的插队
a.线程的让步
Thread.yield()
礼让只是比自己优先级高或者同级别的
如果不满足这个条件该方法失效
抢到之后只让一次,下次抢到直接执行
b.线程的插队
this.join();
调用方法时,调用线程将被阻塞,直到join()方法加入的join方法执行完成。
让给谁,谁执行完,我才执行
七.线程的通信
1、需求
启动两个线程:一个线程做普通打印操作(0.5秒打印一次) 另一个线程去监控键盘,
如果有输入则暂停另一个线程的打印,如果在次检测到键盘有输入,继续运行上一个线程
package com.atguigu.demon;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* 此类用于演示线程的通信
*/
public class Demo5 {
public static void main(String[] args) {
Thread51 t1=new Thread51();
t1.start();
Thread52 t2=new Thread52();
t2.start();
Thread53 t3=new Thread53();
t3.start();
}
}
class Thread51 extends Thread{
public static boolean flag=false;
@Override
public void run() {
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(flag){
//让当前线程暂停(等待)
synchronized ("java") {
try {
"java".wait();//Object
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println(Math.random());
}
}
}
class Thread53 extends Thread{
public static boolean flag=false;
@Override
public void run() {
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(flag){
//让当前线程暂停(等待)
synchronized ("java") {
try {
"java".wait();//Object
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("Thread53-----------"+Math.random());
}
}
}
class Thread52 extends Thread{
@Override
public void run() {
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
try {
in.readLine();
//需要改变flag的值
Thread51.flag=true;
Thread53.flag=true;
in.readLine();
Thread51.flag=false;
Thread53.flag=false;
synchronized ("java") {
// "java".notify();//唤醒在"java"这个对象下等待的线程
"java".notifyAll();//唤醒所有在"java"这个对象下等待的线程
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. 方法
wait(); 等待 (出现在哪个线程中哪个线程等待)
"java".notify();//唤醒在"java"这个对象下等待的线程 每次只能唤醒一个
"java".notifyAll();//唤醒所有在"java"这个对象下等待的线程
特点:
必须用在synchronized方法或synchronized代码块中,
这三个方法全部来自于Object类
八.线程的创建方式三
1、第三种创建方式
a 新建一个接口
b 实现一个接口Callable<方法的返回值>
c 实现抽象方法Call()
启动方式 :
创建对象:FutureTask<String> ft=new FutureTask<>(new Thread61());
使用Thread类进行包装:Thread t=new Thread(ft);
调用start方法启动:t.start();
如何拿到返回值
String str=ft.get();//返回类型默认是泛型类型
特点:
主要是和第二种创建方式的对比
a. 支持泛型
b. 不需要手动处理异常
c. 有返回值
FutureTask<String> ft=new FutureTask<>(new Thread61());
Thread t=new Thread(ft);
t.start();//运行的是call方法
//返回值如何拿
try {
String str=ft.get();
System.out.println("-----------"+str);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
class Thread61 implements Callable<String>{
@Override
public String call() throws Exception {
String str="java";
for (int i = 0; i < 10; i++) {
str+=i;
System.out.println(str);
}
return str;
}
}
九.线程的创建方式四(线程池)
2. 第四种创建方式 (线程池) 数据库连接池
a. 创建了一个线程池容量为5
ExecutorService es=Executors.newFixedThreadPool(5);
b. submit(Runnable/Callable<>); 添加子线程 直接就启动
c. 关闭资源
es.shutdown();
public class Demo6 {
public static void main(String[] args) {
//第四种创建方式
//1. 创建了一个线程池容量为5
ExecutorService es=Executors.newFixedThreadPool(5);
//2. 添加子线程
es.submit(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("----------"+i);
}
}
});
es.submit(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(">>>>>>>>>>"+i);
}
}
});
//3. 关闭
es.shutdown();
}
}
javasE--基础部分--线程的更多相关文章
- javaSE基础07
javaSE基础07 一.static静态修饰符 用了static修饰的变量就会变成共享的属性,只会初始化一次,在内存中只存在一个,并且每个对象都可以访问,存放在方法区(数据共享区) 1.1 stat ...
- javase基础复习攻略《十》
按照计划本篇为大家总结JAVA的网络编程,什么叫网络编程呢?网络编程!=网站编程,对于这一点大家一定要注意,很多小朋友都曾经这么认为.既然谈到网络编程,咱们先了解一下网络的基础知识,什么是计算机网络? ...
- 基础1 JavaSe基础
JavaSe基础 1. 九种基本数据类型的大小,以及他们的封装类 boolean 无明确指定 Boolean char 16bits Character byte 8bits Byte short 1 ...
- JavaSE基础:集合类
JavaSE基础:集合类 简单认识类集 我们学习的是面向对象语言,而面向对象语言对事物的描述是通过对象体现的,为了方便对多个对象进行操作,我们就必须把这多个对象进行存储. 而要向存储多个对象,就不能是 ...
- javaSE基础06
javaSE基础06 一.匿名对象 没有名字的对象,叫做匿名对象. 1.2匿名对象的使用注意点: 1.我们一般不会用匿名对象给属性赋值的,无法获取属性值(现阶段只能设置和拿到一个属性值.只能调用一次方 ...
- javaSE基础05
javaSE基础05:面向对象 一.数组 数组的内存管理 : 一块连续的空间来存储元素. Int [ ] arr = new int[ ]; 创建一个int类型的数组,arr只是一个变量,只是数组的一 ...
- javaSE基础04
javaSE基础04 一.三木运算符 <表达式1> ? <表达式2> : <表达式3> "?"运算符的含义是: 先求表达式1的值, 如果为真, ...
- javaSE基础03
javaSE基础03 生活中常见的进制:十进制(0-9).星期(七进制(0-6)).时间(十二进制(0-11)).二十四进制(0-23) 进制之间的转换: 十进制转为二进制: 将十进制除以2,直到商为 ...
- javaSE基础02
javaSE基础02 一.javac命令和java命令做什么事情? javac:负责编译,当执行javac时,会启动java的编译程序,对指定扩展名的.java文件进行编译,生成了jvm可以识别的字节 ...
- JavaSE基础01
JavaSE基础篇01 ------从今天开始,我就学习正式java了,O(∩_∩)O哈哈~,请大家多指教哦 一.Windows常见的dos命令 操作dos命令: win7 --->开始 --- ...
随机推荐
- C# interact with Command prompt
using System.IO; using System.Diagnostics; static void Main(string[] args) { CmdDemo("dir" ...
- c# 使用T4模板生成实体类(sqlserver)
新建类库,右键添加 "文本模板" 添加完成之后生成如下后缀为 tt的文件: 双击文件:TextTemplate_Test.tt 文件打开,替换代码如下 <#@ templat ...
- sklearn.metrics中的评估方法
https://www.cnblogs.com/mindy-snail/p/12445973.html 1.confusion_matrix 利用混淆矩阵进行评估 混淆矩阵说白了就是一张表格- 所有正 ...
- PAT (Advanced Level) Practice 1006 Sign In and Sign Out (25 分) (排序)
At the beginning of every day, the first person who signs in the computer room will unlock the door, ...
- 2019.2.21 T2题解
meet 大概思路就是 , 找出相交的路径 , 判断方向 , 分类讨论.. 假设已经找出了相交路径 ... 若方向相同 , 则找到相交路径上边权的最大值 , 若最大值>出发时间差 , 则可行. ...
- Net项目添加 WebAPI
1.新建一个 WebApiConfig.cs public static void Register(HttpConfiguration config) { // Web API 配置和服务 // ...
- centos7最小版配置
配置启用dns cd /etc/sysconfig/network-scripts/ vi ifcfg-ens33 # 修改ONBOOT为yes ONBOOT=yes 重启系统 reboot 安装ne ...
- 性能优化-css,js的加载与执行
前端性能优化 css,js的加载与执行 javascript是单线程的 一个网站在浏览器是如何进行渲染的呢? html页面加载渲染的过程 html渲染过程的一些特点 顺序执行,并发加载 词法分析 并发 ...
- 酷卓 一键ROOT教程
待编辑,还没写完 哈哈 酷卓 一键ROOT教程 首先简单介绍下酷卓. 酷卓由我个人开发,主要为了用户获取ROOT简单化,傻瓜化.酷卓获取方式:加QQ群 766969447 群文件下载就行 1. 手动选 ...
- navicat 连接报2059错误
原因 navicat不支持mysql新版本的加密规则,mysql8 之前的版本中加密规则是mysql_native_password, mysql8之后,加密规则是caching_sha2_passw ...