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 --->开始 --- ...
随机推荐
- 关于form表单提交数据后不跳转页面+ajax接收返回值的处理
1.前台的form表单建立,注意action.enctype的内容, 2.通过添加一个隐藏的iframe标签使form的target指向iframe来达到不跳转页面的效果,同时需要在js里获取ifra ...
- LOJ #3119. 「CTS2019 | CTSC2019」随机立方体 组合计数+二项式反演
好神的一道计数题呀. code: #include <cstdio> #include <algorithm> #include <cstring> #define ...
- 欢迎来到ZhuSenlin的博客
置顶说明: 本博客的目的:为了巩固自己所学知识,努力提高自己的专业技能:若文章能够帮助到你,是我莫大的荣幸. 本博客的文章主要涉及的领域为游戏开发(本人不才,也在努力学习中) 随笔主要记录一些琐碎的知 ...
- AE开发中添加EngineOrDesktop后仍然有错误
.AO是32位原生组件,一般认为不支持64位系统(道听途说),所以只能在32位环境下进行编译. 在配置管理器中,新建x86后问题解决了
- Codeforces 1303E. Erase Subsequences 代码(dp 字符串压缩一维状态优化)
https://codeforces.com/contest/1303/problem/E #include<bits/stdc++.h> using namespace std; ; i ...
- spring-framework核心接口ApplicationContext
核心接口(ApplicationContext) 继承关系 继承接口: org.springframework.beans.factory.ListableBeanFactory:用于访问应用程序组件 ...
- web服务器、Web中间件和Web容器的区别
web服务器>web中间件>web容器 Tomcat(servlet容器) 是 Tomcat中间件 也是 Tomcat服务器 看了谢公子的csdn文章,让我彻底分清了这三者的区别. ...
- Java8之Stream详解
Java8中提供了Stream对集合操作作出了极大的简化,学习了Stream之后,我们以后不用使用for循环就能对集合作出很好的操作. 一.流的初始化与转换 Java中的Stream的所有操作 ...
- 《深入理解java虚拟机》读书笔记九——第十章
第十章 早期(编译期)优化 1.Javac的源码与调试 编译期的分类: 前端编译期:把*.java文件转换为*.class文件的过程.例如sun的javac.eclipseJDT中的增量编译器. JI ...
- 事件&vue修饰符
JavaScript 事件 HTML事件是发生在HTML元素上的事情.当在HTML页面帐使用JavaScript时,javascript可以触发这些事件 HTML 事件 HTML事件可以是浏览器的行为 ...