标签(空格分隔): 线程运行状态


线程的运行状态:

如下是是我编写的一个图,大家可以作为参考:



1.new一个thread子类也是创建了一个线程;

2.创建完毕之后start()-----运行,

3.然后从运行-------sleep(time)----冻结----sleep(time)时间到了,恢复到运行;

4.还有一种,是线程运行的时候------wait时间------到冻结状态-------然后notify()唤醒-----然后恢复到运行状态;

5.消亡:线程运行中/冻结:stop()/run方法结束---------消亡;

6.临时状态:当前状态等待CPU的执行权,具备运行资格没有执行权,

7.冻结:放弃了执行资格;

8.冻结状态-----恢复---临时状态/运行状态;

获取线程的对象和名称:

创建了对象之后,都要匹配一个名称,线程的名称都要定义在线程的事物里面:

class Demo extends Thread{
private String name;
Demo(String name){
this.name=name;
}
public void run(){//将运行的代码放在run方法中
for(int x=0;x<60;x++) {
System.out.println(this.getName()+"demo run-----"+x);
}
}
}
class ThreadDemo{ public static void main(String[] args){
Demo d1= new Demo("one");//创建好一个线程
Demo d2= new Demo("two");
d1.start();
d2.start();
for(int x=0;x<60;x++){
System.out.println("helloworld!----"+x);
}
}
}
  • 原来线程都有自己默认的名称,Thread-编号,该编号从零开始;

    2.上述的名称是不是不太好看,这里可以使用set方法来定义名称;

获取当前线程的名称:

  • static Thread currentThread():获取当前线程的对象;

    getName():获取线程名称;

    设置线程名称:setName或者构造方法;

练习:

  • 需求是一个简单的卖票程序,多个窗口卖票,1号窗口在卖的时候,2号也在卖;多个窗口同时卖票,

观察如下的程序:

class Ticket extends Thread{
private int tick=100;
public void run(){
while (true){
if(tick>0) {
System.out.println(Thread.currentThread().getName()+"sale:" + tick--);
}
}
} }
class TickDemo{
public static void main(String[] args){
Ticket t1=new Ticket();
Ticket t2=new Ticket();
Ticket t3=new Ticket();
Ticket t4=new Ticket();
t1.start();
t2.start();
t3.start();
t4.start();
}
}

执行结果:

发现100个票,卖出去了400张票;每个对象里面包含了100张票;

如何实现:100张票4个窗口正常售卖呢?,我们可以通过static定义变量来实现,如下

class Ticket extends Thread{
private static int tick=100;
public void run(){
while (true){
if(tick>0) {
System.out.println(Thread.currentThread().getName()+"sale:" + tick--);
}
}
} }
class TickDemo{
public static void main(String[] args){
Ticket t1=new Ticket();
Ticket t2=new Ticket();
Ticket t3=new Ticket();
Ticket t4=new Ticket();
t1.start();
t2.start();
t3.start();
t4.start();
}
}

执行通过;

  • 但是一般我们不使用静态,因为静态的生命周期比较长;
  • 我们使用Thread创建线程不能实现了;

runable接口:

  • Runable接口应该由那些打算通过某一线程执行实例的类来实现,类必须顶一个称为run的无参数方法,设计该接口的目的就是提供一个公共协议,例如,Thread类实现了Runable,激活的意思是某个线程已经启动并且尚未停止;

class Ticket implements Runnable{
private static int tick=100;
public void run(){
while (true){
if(tick>0) {
System.out.println(Thread.currentThread().getName()+"sale:" + tick--);
}
}
} }
class TickDemo{
public static void main(String[] args){
// Ticket t1=new Ticket();
// Ticket t2=new Ticket();
// Ticket t3=new Ticket();
// Ticket t4=new Ticket();
// t1.start();
// t2.start();
// t3.start();
// t4.start();
Ticket t=new Ticket();
Thread t1=new Thread();
Thread t2=new Thread();
Thread t3=new Thread();
Thread t4=new Thread();
t1.start();
t2.start();
t3.start();
t4.start(); }
}

上述代码:能否实现呢?

分析:t1调用运行的run()是Thread里面的run,在这次代码里面未重写;

package com.wangaling;
class Ticket implements Runnable{
private static int tick=100;
public void run(){
while (true){
if(tick>0) {
System.out.println(Thread.currentThread().getName()+"sale:" + tick--);
}
}
} }
class TickDemo{
public static void main(String[] args){
// Ticket t1=new Ticket();
// Ticket t2=new Ticket();
// Ticket t3=new Ticket();
// Ticket t4=new Ticket();
// t1.start();
// t2.start();
// t3.start();
// t4.start();
Ticket t=new Ticket();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
Thread t4=new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start(); }
}

执行结果:

上述代码可以正常实现售票的功能;

创建线程的第二种方式,实现runnable接口

步骤1:

1。定义类实现Runable接口;

2.覆盖Runable接口中的run方法:将线程要运行的代码存在在run方法中

3.通过Thread类建立线程对象

4.将Runable接口的子类对象作为实际参数传递给Thread类的构造函数:为什么要将Runable接口的子类的对象传递给Thread的构造函数,因为,自定义的run方法所属的对象是Runable接口的子类对象,所以要让线程去指定指定对象的run方法,就必须明确该run方法所属的对象;

5.调用Thread类的start方法开启线程,并调用Runable接口子类的run方法;

实现方式和继承方式有很么区别?

  • 1.实现方式好处:避免了单继承的局限性,在定义线程的时候建议是用实现方式,可以避免单继承的实现性;

两种方式区别:

  • 继承Thread:线程代码存放在Thread子类的run方法中;

    实现Runable,线程代码存在接口的子类的run方法

上述程序的分析:

1。通过分析发现:打印票会出现:0,-1,-2等错票;

多线程的运行出现了安全问题:

  • 问题的原因:

    当多条语句在操作同一个线程共享数据时,一个线程对多条语句执行了一部分还没有执行完另一个线程已经参与进来了,导致了共享数据的错误

    解决办法:

    对多条操作共享数据的语句,只能让一个线程都执行完毕,在执行过程中,其他线程不可以执行;(就是说拿到了执行权也不让他执行)
  • java对多线程提供了专业的解决方式,就是同步代码块,

    synchronized(对象){

    需要被同步的代码块,怎么判断哪些代码块需要同步,就看谁操作了共享数据;

    }

    对象如同锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获得了CPU的执行权限,也进不去,因为没有获取锁;--理解这个概念可以理解火车上的卫生间;
  • 同步的前提:

    1.必须要有2个或者2个以上的线程;

    2.必须多个线程使用一个锁;

    必须保证同步中只有一个线程运行,有些需要同步,有些不需要同步;

    好处:解决多线程的安全问题;

    弊端:每个线程在获取到CPU权限之后,每次都要判断一下锁,这样使程序会变得非常的慢;
package com.wangaling;
class Ticket implements Runnable{
private static int tick=100;
Object obj=new Object();
public void run(){
while (true){
synchronized (obj){
if (tick > 0) {
try(Thread.sleep(10);)catch(Exception e){}
System.out.println(Thread.currentThread().getName() + "sale:" + tick--);
}
}
}
}
}
class TickDemo{
public static void main(String[] args){
// Ticket t1=new Ticket();
// Ticket t2=new Ticket();
// Ticket t3=new Ticket();
// Ticket t4=new Ticket();
// t1.start();
// t2.start();
// t3.start();
// t4.start();
Ticket t=new Ticket();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
Thread t4=new Thread(t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
/*
需求:
银行有一个金库,有两个储户分别存300,每次存100,存3次。
目的:改程序是否有安全问题,如果有,如何解决? 如何找问题:
1.明确哪些代码是多线程运行的代码
2.明确共享数据
3.明确多线程运行代码中哪些语句是操作共享数据的。
*/ class Bank{
private int sum;
Object obj=new Object();
public void add(int n ){
synchronized (obj){
sum=sum+n; try{Thread.sleep(10);}
catch(Exception e){};
System.out.println("sum="+sum);
} } }
class Cus implements Runnable{
private Bank b=new Bank();
public void run(){ for(int x=0;x<3;x++){ b.add(100);
}
} }
class BankDemo{
public static void main(String[] args){ Cus c=new Cus();
Thread t1=new Thread(c);
Thread t2=new Thread(c);
t1.start();
t2.start();
}

如上述的需求我们可以修改为同步函数:

class Bank{
private int sum;
// Object obj=new Object();
public synchronized void add(int n ){
// synchronized (obj){
sum=sum+n; try{Thread.sleep(10);}
catch(Exception e){};
System.out.println("sum="+sum);
// } } }
class Cus implements Runnable{
private Bank b=new Bank();
public void run(){ for(int x=0;x<3;x++){ b.add(100);
}
} }
class BankDemo{
public static void main(String[] args){ Cus c=new Cus();
Thread t1=new Thread(c);
Thread t2=new Thread(c);
t1.start();
t2.start();
}
  • 问题通过上边的学习我们可以对:函数进行同步,那如下同步可以吗?
class Ticket implements Runnable{
private int num=1000;
public synchronized void run(){
while(true) {
if(num>0){ try{ Thread.sleep(10);
}catch (Exception e){}
System.out.println(Thread.currentThread().getName()+"sale"+num--);
} }
}
}
class ThisLockDemo{
public static void main(String[] args){ Ticket t=new Ticket();
Thread t1= new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
t1.start();
t2.start();
t3.start(); }
}
  • 答案不可以,我们可以把run方法体抽离出来单独写一个函数,然后在run里面调用就可以了
class Ticket implements Runnable{
private int num=1000;
public void run(){
while(true){
show();}
}
public synchronized void show(){
if(num>0){
try{
Thread.sleep(10);
}catch (Exception e){}
System.out.println(Thread.currentThread().getName()+"sale"+num--);
}
}
}}
class ThisLockDemo{
public static void main(String[] args){ Ticket t=new Ticket();
Thread t1= new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
t1.start();
t2.start();
t3.start();
}
}
  • 上述的例子:同步函数用的哪锁呢?

    1.函数需要被对象调用,函数都有一个所属对象的引用,就是this,所以同步函数使用的就是this;

    2.通过该程序进行验证,使用两个线程进行卖票,一个线程在同步代码块中,一个在同步函数中,都在执行卖票程序,如果同步不会出现错误的票;
class Ticket implements Runnable{
private int num=1000;
Object obj =new Object();
boolean flag =true;
public void run(){
if (flag){
while(true){
synchronized(this){
if(num>0){
try{
Thread.sleep(10);
}catch (Exception e){}
System.out.println(Thread.currentThread().getName()+"sale"+num--);
}
}
this.show();}
}
}else{
while (true){
show();
}
}
public synchronized void show(){
if(num>0){
try{
Thread.sleep(10);
}catch (Exception e){}
System.out.println(Thread.currentThread().getName()+"sale"+num--);
}
}
}}
class ThisLockDemo{
public static void main(String[] args){ Ticket t=new Ticket();
Thread t1= new Thread(t);
Thread t2=new Thread(t); t1.start();
t1.flag=true;
t2.start();
}
}
  • 如果同步函数被静态修饰后,使用的锁是什么呢?

    通过发现,不是在是this,因为静态方法也不可以定义this,静态进内存是,内存中没有本类对象,但是一定有该类对应额字节码文件对象;

    类名,class,该对象的类型是Class;

    静态同步方法,使用的锁是该方法,所在类字节码文件对象,类名class;
class Ticket implements Runnable{
private int num=1000;
boolean flag =true;
public void run(){
if (flag){
while(true){
synchronized(Ticket.class){
if(num>0){
try{
Thread.sleep(10);
}catch (Exception e){}
System.out.println(Thread.currentThread().getName()+"sale"+num--);
}
}
this.show();}
}
}else{
while (true){
show();
}
}
public synchronized void show(){
if(num>0){
try{
Thread.sleep(10);
}catch (Exception e){}
System.out.println(Thread.currentThread().getName()+"sale"+num--);
}
}
}}
class ThisLockDemo{
public static void main(String[] args){ Ticket t=new Ticket();
Thread t1= new Thread(t);
Thread t2=new Thread(t); t1.start();
t1.flag=true;
t2.start();
}
}

死锁:

同步中嵌套同步,而锁确不同;

class Ticket implements Runnable{
private int num=1000;
Object obj=new Object();
boolean flag =true;
public void run(){
if (flag){
while(true){
synchronized(obj){
if(num>0){
try{
Thread.sleep(10);
}catch (Exception e){}
System.out.println(Thread.currentThread().getName()+"sale"+num--);
}
}
this.show();}
}
}else{
while (true){
show();
}
}
public synchronized void show(){
synchronized(obj){
if(num>0){
try{
Thread.sleep(10);
}catch (Exception e){}
System.out.println(Thread.currentThread().getName()+"sale"+num--);
}
}
}} class ThisLockDemo{
public static void main(String[] args){ Ticket t=new Ticket();
Thread t1= new Thread(t);
Thread t2=new Thread(t); t1.start();
t1.flag=true;
t2.start();
}
}

java学习之- 线程运行状态的更多相关文章

  1. Java学习笔记 线程池使用及详解

    有点笨,参考了好几篇大佬们写的文章才整理出来的笔记.... 字面意思上解释,线程池就是装有线程的池,我们可以把要执行的多线程交给线程池来处理,和连接池的概念一样,通过维护一定数量的线程池来达到多个线程 ...

  2. java学习之线程

    一.线程总述: 线程是java当中一个重要的内容,如果想说线程的话,那我们应该先来讲一下什么是进程. 进程:那么什么是进程呢,进程从字面上来理解就是,正在进行的程序.就比如说我们在windows当中打 ...

  3. java学习之线程池的实现

    package com.gh.threadpoor; import java.util.concurrent.ExecutorService; import java.util.concurrent. ...

  4. Java 学习笔记 线程控制

    题目一 本质上来说,线程是不可控制的,线程的执行是由CPU资源分配决定的,我们无法干预系统CPU的资源分配,但我们可以增加条件来让线程按照我们的预想顺序来执行. 比如.如果当前的执行的线程不满足我们所 ...

  5. java学习之- 线程继承Thread类

    标签(空格分隔): 线程 在java.lang包中有个Thread子类,大家可以自行查阅文档,及范例: 如何在自定义的代码中,自定义一个线程呢? 1.通过对api的查找,java已经提供了对线程这类事 ...

  6. Java学习:线程池

    线程池 线程池概念:其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多的资源. 线程池:容器-->集合(ArrayList,Hash ...

  7. Java学习:线程的安全问题

    线程的安全问题 模拟卖票案例创建三个的线程,同时开启,对共享的票进行出售 public class RunnableImpl implementsc Runnable{ //定义一个多线程共享的票源 ...

  8. Java学习:线程实现方式

    线程实现方式 并发与并行 并发:指两或多个事件在同一个时间段内发生 并行:指两或多个事件在同一个时刻发生(同时发生) 进程的概念 内存:所有的应用程序都需要进入到内存中执行 临时存储RAM 硬盘:永久 ...

  9. java学习笔记 - 线程池(一)

    线程池(Thread Pool):把一个或多个线程通过统一的方式进行调度和重复使用的技术,避免了因为线程过多而带来使用上的开销 优点:(面试题)可重复使用已有线程,避免对象创建.消亡和过度切换的性能开 ...

随机推荐

  1. restapi(2)- generic restful CRUD:通用的restful风格数据库表维护工具

    研究关于restapi的初衷是想搞一套通用的平台数据表维护http工具.前面谈过身份验证和使用权限.文件的上传下载,这次来到具体的数据库表维护.我们在这篇示范里设计一套通用的对平台每一个数据表的标准维 ...

  2. JavaOOP 第二章继承

    一 继承的概念 继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类. 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具 ...

  3. 2. Java基本数据类型及运算符

    1. 计算机数制 1.1 计算机信息单位 阅读二进制.字节.字长,回答以下问题: 1. 计算机中采用什么进制存储信息,它的优点是什么 2. 什么是位.字节 3. K.M.G.T.P之间的转换 4. 什 ...

  4. 一文掌握 Spring Boot Profiles

    Spring Boot Profiles 简介 Profile 的概念其实很早在 Spring Framework 就有了,在 Spring Framework 3.1 版本引入了注解 @Profil ...

  5. css3系列之详解perspective

    perspective 简单来说,就是设置这个属性后,那么,就可以模拟出像我们人看电脑上的显示的元素一样.比如说, perspective:800px   意思就是,我在离屏幕800px 的地方观看这 ...

  6. MySQL 之 Explain 输出分析

    ​MySQL 之 Explain 输出分析 背景 前面的文章写过 MySQL 的事务和锁,这篇文章我们来聊聊 MySQL 的 Explain,估计大家在工作或者面试中多多少少都会接触过这个.可能工作中 ...

  7. 荔枝FM前端面试题

    最近接到了荔枝FM的面试通知,遗憾的是没有拿到offer,但是这次面试呢,还是收获很大的,下面就来给大家说说我遇到的面试题 一面 一面是直接发了一套面试题到邮箱,开启了防作弊的,限时20分钟做完,下面 ...

  8. 论文阅读 | Falcon: Balancing Interactive Latency and Resolution Sensitivity for Scalable Linked Visualizations

    作者: Dominik Moritz, Bill Howe, Jeffrey Heer 发表于CHI 2019, 三位作者都来自于University of Washington Interactiv ...

  9. Lua语言学习

    1,语法 语句不用分号结尾 function ... end if .. else .. end 2, io库, string库, table库, OS库, 算术库, debug库 3, dofile ...

  10. CSS3: @font-face 介绍与使用

    @font-face 是CSS3中的一个模块,他主要是把自己定义的Web字体嵌入到你的网页中,随着@font-face模块的出现,我们在Web的开发中使用字体不怕只能使用Web安全字体,你们当中或许有 ...