28线程

进程:计算机执行的任务

线程:执行任务中的小任务 多线程

计算机再执行过程中,再同一时间只能让cpu的一个核执行一个进程。进程有多个线程构成,再同一时刻Cpu只能处理一个线程。

引入多线程

  当线程被cpu执行时cpu开始工作,线程需要和软硬件进行交互,这个时候cpu就是处于空闲状态

引用多线程可以提高cpu的使用效率

 

创建多线程的方式-----(Thead)

1.继承Thread类,重写run方法(线程代码逻辑所在的地方,调用start方法,开启线程. 有一个不好的地方就是java是单继承所以我们继承了Thread后就不能继承其他类

,所以我们通常采用第二种方法 实现接口

 

public class ThreadDemo {public static void main(String[] args) {//线程执行---执行线程逻辑所在的类Demo d=new Demo();//标记线程可以被cpu执行
        d.start();for(int i=0;i<10;i++){System.out.println("main:"+i);}}}
//线程任务的执行的代码逻辑
class Demo extends Thread{//重写方法----实现线程的代码逻辑
    @Overridepublic void run() {for(int i=0;i<10;i++){System.out.println("i"+i);}}
}

 

 

 

 2.实现Runnable接口,重写run方法(线程代码逻辑),通过Runnable接口的实现类对象构建Thread类对象,调用start方法开启线程

 

public class ThreadDemo2 {public static void main(String[] args) {//通过Runnable实现类对象构建Thread类对象Thread t=new Thread(new TDemo() );//开启线程
        t.start();for(int i=0;i<10;i++){System.out.println("main:"+i);}}}
//线程代码逻辑所在类,实现Runnable接口
class TDemo implements Runnable{//重写方法 --线程代码逻辑
    @Overridepublic void run() {for(int i=0;i<10;i++){System.out.println("i"+i);}}
}

 

 

3.实现Callable接口,重写call方法(现阶段了解就好)

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;public class ThreadDemo3 {
public static void main(String[] args) throws InterruptedException, ExecutionException {//创建线程类对象DTDemo1 dt=new DTDemo1();//获取执行服务器,ExecutorService e=Executors.newCachedThreadPool();//把你想要操作的东西放到执行服务器上Future<Integer> f =e.submit(dt);System.out.println(f.get());
}
}
//Integer 重写方法返回值类型
class DTDemo1 implements Callable<Integer>{//重写方法----线程代码逻辑所在的地方
    @Overridepublic Integer call() throws Exception {// TODO Auto-generated method stubreturn 20;}}

因为底层多线程之间存在抢占问题,抢占发生再代码的每一步,导致了数据安全问题

为了排除我们多线程的抢占问题我们采用加锁的策略,有两种 1.同步代码块锁,同步方法锁

同步代码块锁--synchtonized(锁对象){} ----锁对象指的是 可以被线程共享--方法区里的内容可以被所有线程共享(对多少个线程对象进行加锁,这些对象都是同步的)

同步方法锁--在方法上加上synchronized,如果这个方法是静态方法锁对象就是类名.class,如果这个方法是非静态方法锁对象就是this,构造器和属性上不能夹synchronized

同步:多个线程每次只能执行一个(一个一个)

异步:多个线程每次可以执行多个(抢占)

同步一定是安全的

安全的不一定是同步

不安全一定是异步

异步不一定不安全

从微观上同步一定是安全的,异步一定是不安全的

 

public class SellTicketDemo {public static void main(String[] args) {//创建票类对象Ticket t=new Ticket();//设置票数t.setCount(100);//四个售票员Seller s1=new Seller(t);Seller s2=new Seller(t);Seller s3=new Seller(t);Seller s4=new Seller(t);//开启线程  并给每个线程new Thread(s1,"A").start();new Thread(s2,"B").start();new Thread(s3,"C").start();new Thread(s4,"D").start();}
}
//模拟卖票的过程---线程的代码逻辑
class Seller implements Runnable{//引入票类
    Ticket t;//有参构造public  Seller(Ticket t) {this.t=t;}//线程的代码逻辑---买票的过程//同步方法锁是直接加在方法上 同步方法锁如果是非静态方法那么他的锁对象是this//如果是静态方法的话,那么锁对象就是类名.class
    @Overridepublic synchronized void run() {while(true){    //同步代码块锁---()中的是锁对象 ----被线程共享,只要是能被所有对象共享的就可以,锁对象必须被所有被执行的线程共享 方法区中的就可以因为方法区(是被所有的线程共享的)但是范围太大了,能小的锁就小得锁synchronized (Seller.class) {if(t.getCount()<=0) //票买完的时候就是票数为0
                {break;}//设置新的票数t.setCount(t.getCount()-1);//打印出具体是那个售票员卖的----具体是那个线程执行的//Thread.currentThread()当前正在执行的线程System.out.println(Thread.currentThread().getName()+"买了一张票,还剩"+t.getCount()+"票");}}}}//表示票类
class Ticket{//属性//票数private int count;public int getCount() {return count;}public void setCount(int count) {this.count = count;}}

 锁之间的相互嵌套----死锁

 

public class DeadLoackDemo {//
    static Print p=new Print();static Scan s=new Scan();public static void main(String[] args) {//开启线程new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stub//打印信息synchronized (p) {p.print();//让线程进行休眠---线程释放执行权try { Thread.sleep(20);} catch (InterruptedException e) {// TODO Auto-generated catch block
                        e.printStackTrace();}//扫描synchronized (s) {s.sacnn();}}}}).start();new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stub//先扫描synchronized (s) {s.sacnn();synchronized (p) {p.print();}}}}).start();}
}//打印机
class Print{public void print(){System.out.println("在打印东西...");}
}//扫描仪
class Scan{public void sacnn(){System.out.println("在扫描信息...");}
}

 

 

 如果破解死锁:上面的死锁出现的问题是两个线程需要同一个锁,如果一个走一个等待那么就不会产生死锁现象,所以我们需要控制锁一个锁走完再让另一个线程获取这个锁

package cn.tedu.thread;public class WaitNotifyDemo {public static void main(String[] args) {//创建学生类对象Student s=new Student();s.setName("lili");s.setGender('女');//开启线程new Thread(new Ask(s)).start();new Thread(new Change(s)).start();}
}//线程所在的类---问问题
class Ask implements Runnable{// 引入学生类对象private Student s;public Ask(Student s){this.s=s;}@Overridepublic void run() {// TODO Auto-generated method stub//表示问问题的结果while(true){synchronized (s) { //防止多线程抢占,保证性别//释放线程执行权---等待if(s.flag==false)try {//让线程等待----相当于堵塞主要是为了挨个回答问题
                    s.wait();} catch (InterruptedException e) {// TODO Auto-generated catch block
                    e.printStackTrace();}//输出
                System.out.println("老师你好,我是"+s.getName()+",是一个"+s.getGender()+"生,想问问题...");//唤醒线程
                s.notify();//改变布尔值s.flag=false;}}}}//线程所在的类---换学生
class Change implements Runnable{//引入学生类对象private Student s;public Change(Student s){this.s=s;}@Overridepublic void run() {// TODO Auto-generated method stubwhile(true){synchronized (s) { //防止多线程的抢占---保证性别//线程等待if(s.flag==true)try {s.wait();} catch (InterruptedException e) {// TODO Auto-generated catch block
                    e.printStackTrace();}//
                if (s.getName().equals("tom")) {s.setName("lili");s.setGender('女');} else {s.setName("tom");s.setGender('男');}//线程唤醒
                s.notify(); //唤醒阻塞的线程,CPU可以将阻塞的线程抢执行权了。//改变布尔值s.flag=true;}}}}//学生类
class Student{//属性private String name;private char gender;//
    boolean flag=true;public char getGender() {return gender;}public void setGender(char gender) {this.gender = gender;}public String getName() {return name;}public void setName(String name) {this.name = name;}}

 wait、notify、notifyAll是线程中通信可以使用的方法。线程中调用了wait方法,则进入阻塞状态,只有等另一个线程调用与wait同一个对象的notify方法。这里有个特殊的地方,调用wait或者notify,前提是需要获取锁,也就是说,需要在同步块中做以上操作。

 

 等待唤醒的前提唤醒一个 是得有锁

notify()随机唤醒 肯定给你唤醒一个 作用 唤醒阻塞的线程,CPU可以将阻塞的线程抢执行权了。两个对象的话就是一个线程执行一次,因为只有一种情况,一个线程再执行,另一个再阻塞

wait和sleep的区别

sleep--用于是线程进入休眠状态(需要制定休眠的时间,到了这个时间才会唤醒),在其s0leep时间段内,该线程不会获得执行的机会,即使系统种没有其他可以运行的线程如果线程没有加锁,就会释放线程的执行权,如果加锁就不会释放执行权,但是会有CPU的切换 ,可以指定休眠时间 这是Thread的静态方法

wait---如果指定等待时间,就必须等到时间结束才能唤醒,如果不指定时间就只能手动唤醒,如果线程加锁就会释放锁也能释放执行权,如果没有加锁就释放执行权,是Object里的普通方法

线程状态:

当线程被创建并启动以后,它既不是以启动就进入了执行状态,也不是一致处于执行状态,在线程的生命周期中,他要径路新建,就绪,运行,阻塞和死亡5种状态。 尤其是线程启动以后,它不能一直“霸占”

着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换

1.新建:当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时它和其他java对象一样,仅仅有java虚拟机为其分配了内存,并初始化了其成员变量的值。此时的线程对象没有表现出任何线程的动态特征,程序也不会执行线程的线程执行体。

2.就绪状态:当线程对象调用了start()方法之后,该线程处于就绪状态,java虚拟机会为其创建方法调用栈和程序计数器,处于这个状态下的线程并没有开始运行,它只是表示该线程可以运行了,至于该线程何时开始运行,取决于jvm里线程调度器的调度

不要对已经处于启动状态的线程再次调用start方法,否则将引发IllegalThreadStateException异常

如果程序希望调用子线程的start()方法后子线程立即开始执行,程序可以使用Thread.sleep(1)来让当前运行的线程(主线程)睡眠一毫秒---1毫秒就够了,因为在这1毫秒内CPU不会空闲,它就会去执行另一条就绪状态的线程,这样就可以让我们的子线程立即获得执行

 

 

 

 

 

 

 

守护线程

需要手动开启,如果被守护线程执行结束,守护线程也随着结束,反之不是 如果有多个线程,除了守护

线程,其他的都是被守护线程 ,java中最大的守护线程是GC

package cn.tedu.thread;public class DemonDemo {public static void main(String[] args) {//创建出小兵对象Thread t1=new Thread(new Soilder(),"小兵1");Thread t2=new Thread(new Soilder(),"小兵2");Thread t3=new Thread(new Soilder(),"小兵3");Thread t4=new Thread(new Soilder(),"小兵4");//设置守护线程t1.setDaemon(true); //true代表手动开启守护线程t2.setDaemon(true);t3.setDaemon(true);t4.setDaemon(true);//开启线程
        t1.start();t2.start();t3.start();t4.start();//被守护线程for(int i=10;i>=0;i--){System.out.println("boss剩余"+i);}}}//线程类---小兵
class Soilder implements Runnable{@Overridepublic void run() {// TODO Auto-generated method stub//输出每个小兵的剩余血量for(int i=10;i>=0;i--){System.out.println(Thread.currentThread().getName()+"还剩"+i+"滴血...");}//线程走的太快就让慢点,方便自己查看结果try {Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch block
            e.printStackTrace();}}}

前台线程死亡后,jvm会通知后台线程死亡,但从它接受命令,到它做出响应,需要一定时间,而且要将某个线程设置为后台线程,必须在该线程启动之前设置,也就是说setDaemon(true)必须在start()方法调用之前否则会引发IllegalThreadStateException

 

 

线程优先级:

优先级(1-10),理论上优先级越大越有机会抢到执行权,理论上如果线程1与线程2之间的优先级之差大于5,那么线程1强到执行权的机会比线程2大一点。就算你设置成10和1差距也不大,功能比较鸡肋

package cn.tedu.thread;public class PririotyDemo {public static void main(String[] args) {Thread t1=new Thread(new PDemo(),"A");Thread t2=new Thread(new PDemo(),"B");//设置优先级t1.setPriority(1);t2.setPriority(9);//开启线程
        t1.start();t2.start();}}class PDemo implements Runnable{@Overridepublic void run() {// TODO Auto-generated method stubfor(int i=0;i<10;i++){System.out.println(Thread.currentThread().getName());}}//
}

 生产者和消费者问题

 

//生产消费模型
public class WaitNotifyText {public static void main(String[] args) {//商品对象Product p=new Product();//开启线程new Thread(new Productor(p)).start();new Thread(new Productor(p)).start();new Thread(new Consumer(p)).start();new Thread(new Consumer(p)).start();}
}//模拟生产过程---线程逻辑代码
class Productor implements Runnable{//引入商品类
    Product p;public Productor(Product p){this.p=p;}//重写
    @Overridepublic void run() {while (true) {synchronized (p) {while(p.flag==true)//加上while保证线程一定会进行判断try {p.wait();} catch (InterruptedException e) {// TODO Auto-generated catch block
                        e.printStackTrace();}// TODO Auto-generated method stub// 此时生产的最大值int max = 1000 - p.getNum();// 减去上次剩余// 随机生产的商品数量int count = (int) (Math.random() * (max + 1));// 设置新的商品数量p.setNum(p.getNum() + count);// 输出System.out.println("此次生产了" + count + "个商品,还剩余" + p.getNum() + "个商品...");//唤醒//p.notify();//随机唤醒一个
                p.notifyAll();p.flag=true;}}}}//模拟消费过程
class Consumer implements Runnable{// 引入商品类
    Product p;public Consumer(Product p){this.p=p;}@Overridepublic void run() {// TODO Auto-generated method stubwhile (true) {synchronized (p) {while(p.flag==false)try {p.wait();} catch (InterruptedException e) {// TODO Auto-generated catch block
                        e.printStackTrace();}// 此次消费最大值int max = p.getNum();// 此次消费的随机商品数量int count = (int) (Math.random() * (max + 1));// 设置新的商品数量p.setNum(p.getNum() - count);// 输出System.out.println("此次消费了" + count + "个商品,还剩余" + p.getNum() + "个商品...");//唤醒//p.notify();
                p.notifyAll();p.flag=false;}}}}//商品类
class Product{//商品数量private int num;//
    boolean flag=true;public int getNum() {return num;}public void setNum(int num) {this.num = num;}}

 

转载于:https://www.cnblogs.com/xuwangqi/p/11249416.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/349887.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是javax.ws.rs.core.context? [第3部分]

如何使用Context批注 在什么是javax.ws.rs.core.context的第2部分中&#xff1f; 您学习了如何使用Context批注从SecurityContext类的注入实例检索安全信息&#xff0c;以及如何通过ResourceContext实例使用JAX-RS资源类。 在本文中&#xff0c;您将学习如何将Context批注与请…

html 字幕飘动效果,html 滚动字幕 制作滚动字幕效果 参数

制作滚动字幕效果&#xff1a;marquee标签 如下:&#xff1c;MARQUEE directionup height146 οnmοuseοutstart() οnmοuseοverstop() scrollAmount4&#xff1e; &#xff1c;/marquee&#xff1e;参数说明&#xff1a;direction滚动方向&#xff1a;up向上滚动&#xff0…

静态点分治总结

点分治是世界上最好的算法QwQ 点分治可以解决各种树上的边权点权问题&#xff0c;然后如果你发现这个题好像问的特别玄学&#xff0c;lca&#xff0c;树差都做不了&#xff0c;树上动‘龟’更做不了&#xff0c;只能暴力时&#xff0c;这个题大多数情况就是点分治了 点分治的思…

html节点上下移动,关于前端:数组元素上下移动

/*** 上、下挪动* param {number} code 下标* param {number} dir 1上移 0下移*/onMove(code, dir) {let moveComm (curIndex, nextIndex) > {let arr this.commodityInfoarr[curIndex] arr.splice(nextIndex, 1, arr[curIndex])[0]return arr}this.commodityInfo.some((…

mybatis插入数据后返回自增主键ID详解

1.场景介绍: ​ 开发过程中我们经常性的会用到许多的中间表,用于数据之间的对应和关联.这个时候我们关联最多的就是ID,我们在一张表中插入数据后级联增加到关联表中.我们熟知的mybatis在插入数据后返回的是插入成功的条数,那么这个时候我们想要得到相应的这条新增数据的ID,该怎…

spring 属性占位符_Spring属性占位符配置器–一些不太明显的选项

spring 属性占位符Spring的PropertySourcesPlaceholderConfigurer用于从XML或Java Config中定义的Spring bean定义外部化属性。 PlaceholderConfigurer支持的一些选项在文档中并不明显&#xff0c;但很有趣&#xff0c;并且可能有用。 首先&#xff0c;以Spring文档中的示例为…

红包雨效果html,js+css实现红包雨效果

//每一个红包都是相对于父元素定位&#xff0c;通过z-index来设置层级let zIndex 1;function bindEvent() {$redPackage.on(click,.js-RedPackageBox,function() {//拿到每个红包的数据const data $(this).data(txt);}}//生成mix-max的随机数function getRandom(min,max) {re…

Delphi下实现全屏快速找图找色 二、矩阵遍历

二、矩阵遍历  矩阵遍历是一个数据结构方面的问题。假设有一个矩阵Matrix&#xff0c;它共有RowCount行&#xff0c;每行有ColCount列&#xff0c;当利用y表示行数&#xff0c;x表示列数&#xff0c;那么利用Matrix[y,x]就可以访问矩阵中的任意元素。假设有一个1010大小的矩阵…

Eclipse MicroProfile:您需要了解的5件事

针对微服务架构优化企业Java Eclipse MicroProfile计划是在JavaOne 2016上发起的&#xff0c;JavaOne是服务器供应商和Java用户组的创意&#xff0c;目的是解决企业Java微服务领域的缺点。 Java EE的发布速度减慢到无法应对Swift发展的微服务趋势的挑战的程度。 MicroProfile通…

html 选择不能重复,人生,就是一次无法重复的选择(深度好文)

作者&#xff1a;彩云追月欧洲著名的政治家托马斯 莫尔说&#xff1a;“在人生中最艰难的是选择”。漫漫人生路&#xff0c;有无数的选择&#xff0c;不同的选择&#xff0c;可能会决定我们不同的人生道路。下面的故事也许对你有所启迪&#xff1a;一天&#xff0c;几个学生问…

用HTML做软件UI用到的的一些技术

做WEB开发的想把网页做成应用程序的界面&#xff0c;开发应用程序的又想把程序界面做得和WEB一样。本文介绍一下用HTML做软件UI用到的的一些技术。 其实HTML UI也不是什么新鲜事了&#xff0c;Norton Antivirus从几年前的版本就开始用了&#xff0c;vs.net2002中的开始页也用了…

html css导航栏字体图标,HTML+CSS入门之两种图标字体库

本篇教程介绍了HTMLCSS入门之两种图标字体库&#xff0c;希望阅读本篇文章以后大家有所收获&#xff0c;帮助大家HTMLCSS入门。<## 0. 前言比较基础的图标加载&#xff1a;和块元素的背景background: url(./x.png).页面多图标时&#xff0c;使用雪碧图(多个png压缩成一个png…

垃圾收集算法,垃圾收集器_弱,弱,最弱,利用专家参考来管理垃圾收集器

垃圾收集算法,垃圾收集器何时以及何时不使用Java中的专家引用 弱引用&#xff0c;软引用和幻像引用既危险又强大。 如果以错误的方式使用它们&#xff0c;则会破坏JVM性能。 但是&#xff0c;如果使用正确的方法&#xff0c;它们可以大大提高性能和程序清晰度。 弱引用和软引用…

ESP8266—“ICACHE_FLASH_ATTR”宏

问&#xff1a;ESP8266_NONOS_SDK中ICACHE_FLASH_ATTR宏的用途是什么&#xff1f;我看到它取决于ICACHE_FLASH&#xff0c;但我不知道何时应该定义该符号。什么时候需要包括它&#xff1f;答&#xff1a;对于ESP8266_NONOS_SDK&#xff0c;用ICACHE_FLASH_ATTR编译的函数编译到…

layui网页html编辑器,layui使用富文本编辑器

HTML代码&#xff1a;这里的原理是你输入的内容会经过处理插入到文本区域textarea中js代码&#xff1a;/*** 文本编辑器*/layui.use([form, layedit], function(){var layedit layui.layedit;//上传图片,必须放在 创建一个编辑器前面layedit.set({uploadImage: {url: upload /…

Java应用程序性能监视:复杂的分布式应用程序的端到端性能

通过从应用程序中学习企业APM产品&#xff0c;发现更快&#xff0c;更高效的性能监控。 参加AppDynamics APM导览&#xff01; 在最复杂和分布式环境中端到端监视Java应用程序性能-专注于业务事务。 自动发现的业务交易&#xff0c;动态基准&#xff0c;代码级诊断和虚拟作战室…

C#设计模式(2)——简单工厂模式

一、引言 这个系列也是自己对设计模式的一些学习笔记,希望对一些初学设计模式的人有所帮助的,在上一个专题中介绍了单例模式,在这个专题中继续为大家介绍一个比较容易理解的模式——简单工厂模式。 二、简单工厂模式的介绍 说到简单工厂&#xff0c;自然的第一个疑问当然就是什…

计算机应用基础课程基本要求,计算机应用基础课程标准

《计算机应用基础》课程标准一、课程性质&#xff1a;《计算机应用基础》课程是中职学校各专业学生必修的一门公共基础课程&#xff0c;具有很强的实践性和应用性&#xff0c;是各行各业从事现代化办公、计算机设计及应用等领域人材所必须具备的理论知识和实践技能。通过本课程…

S3C2410 bootloader ----VIVI阅读笔记 (转)下

1 static inline void mem_mapping_linear(void) 2 { 3 unsigned long pageoffset, sectionNumber; 4 putstr_hex("MMU table base address 0x", (unsigned long) mmu_tlb_base); 5 /* 4G 虚拟地址映射到相同的物理地址. not cacacheable, no…

华南理工网络计算机基础知识,2019年华南理工大学网络教育计算机基础随堂练习题第一章.docx...

计算机基础知识第一节 计算机的基本概念随堂练习提交截止时间&#xff1a;2019-06-15 23:59:59本次练习有题&#xff0c;你已做题&#xff0c;已提交题&#xff0c;其中答对题。当前页有6题&#xff0c;你已做6题&#xff0c;已提交6题&#xff0c;其中答对6题。1.(单选题)? 计…