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--基础部分--线程的更多相关文章

  1. javaSE基础07

    javaSE基础07 一.static静态修饰符 用了static修饰的变量就会变成共享的属性,只会初始化一次,在内存中只存在一个,并且每个对象都可以访问,存放在方法区(数据共享区) 1.1 stat ...

  2. javase基础复习攻略《十》

    按照计划本篇为大家总结JAVA的网络编程,什么叫网络编程呢?网络编程!=网站编程,对于这一点大家一定要注意,很多小朋友都曾经这么认为.既然谈到网络编程,咱们先了解一下网络的基础知识,什么是计算机网络? ...

  3. 基础1 JavaSe基础

    JavaSe基础 1. 九种基本数据类型的大小,以及他们的封装类 boolean 无明确指定 Boolean char 16bits Character byte 8bits Byte short 1 ...

  4. JavaSE基础:集合类

    JavaSE基础:集合类 简单认识类集 我们学习的是面向对象语言,而面向对象语言对事物的描述是通过对象体现的,为了方便对多个对象进行操作,我们就必须把这多个对象进行存储. 而要向存储多个对象,就不能是 ...

  5. javaSE基础06

    javaSE基础06 一.匿名对象 没有名字的对象,叫做匿名对象. 1.2匿名对象的使用注意点: 1.我们一般不会用匿名对象给属性赋值的,无法获取属性值(现阶段只能设置和拿到一个属性值.只能调用一次方 ...

  6. javaSE基础05

    javaSE基础05:面向对象 一.数组 数组的内存管理 : 一块连续的空间来存储元素. Int [ ] arr = new int[ ]; 创建一个int类型的数组,arr只是一个变量,只是数组的一 ...

  7. javaSE基础04

    javaSE基础04 一.三木运算符 <表达式1> ? <表达式2> : <表达式3> "?"运算符的含义是: 先求表达式1的值, 如果为真, ...

  8. javaSE基础03

    javaSE基础03 生活中常见的进制:十进制(0-9).星期(七进制(0-6)).时间(十二进制(0-11)).二十四进制(0-23) 进制之间的转换: 十进制转为二进制: 将十进制除以2,直到商为 ...

  9. javaSE基础02

    javaSE基础02 一.javac命令和java命令做什么事情? javac:负责编译,当执行javac时,会启动java的编译程序,对指定扩展名的.java文件进行编译,生成了jvm可以识别的字节 ...

  10. JavaSE基础01

    JavaSE基础篇01 ------从今天开始,我就学习正式java了,O(∩_∩)O哈哈~,请大家多指教哦 一.Windows常见的dos命令 操作dos命令: win7 --->开始 --- ...

随机推荐

  1. 解决Mac无法写入U盘问题

    注:本文出自博主 Chloneda:个人博客 | 博客园 | Github | Gitee | 知乎 本文源链接:https://www.cnblogs.com/chloneda/p/upan-to- ...

  2. Spark学习之路 (十)SparkCore的调优之Shuffle调优[转]

    概述 大多数Spark作业的性能主要就是消耗在了shuffle环节,因为该环节包含了大量的磁盘IO.序列化.网络数据传输等操作.因此,如果要让作业的性能更上一层楼,就有必要对shuffle过程进行调优 ...

  3. vue.js父组件引入子组件,父组件向子组件传值

    先看看目录结构app.vue为父组件,components里面的文件为子组件 下面这张图是父组件app.vue中的内容 下面这张图是子组件student.vue中的内容 这样父组件中的sdt数据就传入 ...

  4. 解决linux 终端UnicodeDecodeError: 'utf-8' codec can't decode byte 0xce in position 0: invalid continuation byte

    vi   /etc/locale.conf 修改LANG="zh_CN.gbk" 最后执行source /etc/locale.conf 即可永久生效,下次登录,中文就不会乱码了.

  5. Github+Hexo一站式部署个人博客(原创)

    写在前面 注:博主 Chloneda:个人博客 | 博客园 | Github | Gitee | 知乎 本文源链接:https://www.cnblogs.com/chloneda/p/hexo.ht ...

  6. Java设计模式(工厂模式)

    一.简单工厂模式 简单工厂模式就是把对类的创建初始化全都交给一个工厂来执行,而用户不需要去关心创建的过程是什么样的,只用告诉工厂我想要什么就行了.而这种方法的缺点也很明显,违背了设计模式的开闭原则,因 ...

  7. laravel中{{}}和{!! !!}的区别

    1.{{}}和{!! !!} 中{{}}支持转义     一段html代码只是被当成普通的字符串输出 ,{!! !!} 不支持转移  一段html代码可以被正常的解析 1.2具体什么意思呢我们上代码演 ...

  8. npm vs yarn

    npm yarn npm install yarn npm install react --save yarn add react npm uninstall react --save yarn re ...

  9. 粒子群算法优化BP生物能神经网络

    定义: 粒子群中每个粒子的位置表示BP神经网络当前迭代中权值的集合,每个粒子的维数由网络中起连接作用的权值的数量和阈值个数决定,以给定训练样本集的神经网络输出误差作为神经网络训练问题的适应度函数,适应 ...

  10. MySQL的DQL语言(查)

    MySQL的DQL语言(查) DQL:Data Query Language,数据查询语言. DQL是数据库中最核心的语言,简单查询,复杂查询,都可以做,用select语句. 1. 查询指定表的全部字 ...