多线程二(碌碌无为,平平凡凡)
发布日期:2022-04-11 08:52:50
浏览次数:10
分类:技术文章
本文共 10342 字,大约阅读时间需要 34 分钟。
昨天给大家忘了介绍一个方法
线程休眠 public static void sleep(long time) 让线程休眠指定时间,单位为毫秒 代码实现:public class test { public static void main(String[] args) throws InterruptedException { System.out.println("睡觉前"); //没有创建线程就是主线程休眠 Thread.sleep(3000); //先打印睡觉前,等待三秒打印睡醒了 System.out.println("睡醒了"); } }多线程的实现:
public class MyRunnable implements Runnable{ @Override public void run() { for (int i = 0; i < 100; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" "+i); } } }测试类:
public class Demo { public static void main(String[] args) { MyRunnable mr=new MyRunnable(); Thread t1=new Thread(mr); Thread t2=new Thread(mr); t2.start(); t1.start(); } }后台线程/守护线程 为了守护普通线程而存在的 public final void setDaemon(boolean on);设置为守护线程 代码:第一个线程类
public class Thread extends java.lang.Thread { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName()+" "+i); } }}
第二个线程类
public class Thread1 extends Thread{ @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(getName()+" "+i); } }}
测试类:
public class Demo { public static void main(String[] args) { Thread t1=new Thread(); Thread1 t2=new Thread1(); t1.setName("头线程"); t2.setName("尾线程"); //把第二个线程设置为守护线程 //当普通线程执行完之后,那么守护线程也没有继续运行下去的必要了 但不会立马停掉 t2.setDaemon(true); t1.start(); t2.start(); }}
线程安全问题
经典案例 买票 需求:电影院100张票,有三个窗口(三个线程),设计一个程序买票 思路:1.定义一个类实现线程接口,里边定义一个变量,票的总数为100 2.在类中重写run()方法实现买票,代码步骤如下 A.判断票数大于0,就卖票,并告知是那个窗口卖的 B.票数-1 C.卖光线程停止 3.定义一个测试类Demo, 1.创建类对象 2.创建三个线程对象,给出相应线程名称 3.启动线程 代码:public class Runnable implements java.lang.Runnable { //票的数量 private int ticaketCount=100; @Override public void run() { while (true){ if (ticaketCount==0){ //票买完了 break; }else { //Thread.currentThread().getName() 线程名称 //ticaketCount 票的数量 ticaketCount--; System.out.println(Thread.currentThread().getName()+"在买票"+"还剩下"+ticaketCount+"张票"); } } }}Demo测试类:
public class Demo { public static void main(String[] args) { Runnable ra=new Runnable(); //创建一个对象 三个线程 要是创建三个线程的话就是三百张票 Thread t1=new Thread(ra); Thread t2=new Thread(ra); Thread t3=new Thread(ra); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); }}
在现实生活中,出票是需要时间的,所以我们应该加上sleep方法,让每个线程执行完毕等待
public class Runnable implements java.lang.Runnable { //票的数量 private int ticaketCount=100; @Override public void run() { while (true){ if (ticaketCount==0){ //票买完了 break; }else { //Thread.currentThread().getName() 线程名称 //ticaketCount 票的数量 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } ticaketCount--; System.out.println(Thread.currentThread().getName()+"在买票"+"还剩下"+ticaketCount+"张票"); } } }}
public class Demo { public static void main(String[] args) { Runnable ra=new Runnable(); //创建一个对象 三个线程 要是创建三个线程的话就是三百张票 Thread t1=new Thread(ra); Thread t2=new Thread(ra); Thread t3=new Thread(ra); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); }}//窗口2在买票还剩下97张票//窗口1在买票还剩下97张票//窗口3在买票还剩下96张票//窗口2在买票还剩下3张票//窗口1在买票还剩下2张票//窗口3在买票还剩下1张票//窗口2在买票还剩下0张票//窗口1在买票还剩下-1张票//窗口3在买票还剩下-2张票//窗口1在买票还剩下-3张票//窗口3在买票还剩下-4张票//窗口1在买票还剩下-5张票
然后就会出现问题 相同的票 还有负数的票
原因: 重复:线程开始时,三个线程抢占CPU的执行权,线程一抢到执行权,然后票数--为99,假设现在线程三sleep时间到了,抢到了执行权,执行--为98,但是现在线程一未结束,因为操作的同一个线程,所以就时票数都是98,就会出现重复 符号: 假设票为1,第一个线程进去抢到CPU,进入沉睡,但第二个线程也抢到了CPU,由于第一个线程还是Sleep,所以对象没有发生改变,所以就会发生同时为1,但是线程1,结束Sleep方法后,执行--为0,对象发生改变,正在沉睡的线程对象也是0,再次执行--就会是-1,之所以会出现我上述的-2,-3,-4...是因为if判断语句中没有加入ticaketCount>=0 为什么会出现这种问题呢? 多线程操作共享资源 如何解决多线程安全问题呢? 基本思想:让程序没有安全问题的环境 怎么实现? 把多条语句操作共享数据的代码锁起来,让任意时刻只能由一个线程执行即可 JAVA中提供了同步代码块 同步代码块 锁多条语句操作共享数据,可以使用同步代码块实现 格式: synchronized(任意对象){ 多条语句操作共享数据的代码 } 默认情况是打开的,只要有一个线程进去执行代码了,锁就会关闭 当线程执行完毕,锁就自动打开 同步的好处和弊端: 好处:解决了多线程的数据安全问题 弊端:当线程很多时,因为每个线程都会判断同步上的锁,这是很耗费资源的,无形中降低程序的运行效率 代码:public class Runnable implements java.lang.Runnable { //票的数量 private int ticaketCount=100; private Object obj=new Object(); @Override public void run() { while (true){ //锁对象是任意的 , 多个线程必须使用同一把锁 synchronized (obj){ if (ticaketCount==0){ //票买完了 break; }else { //Thread.currentThread().getName() 线程名称 //ticaketCount 票的数量 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } ticaketCount--; System.out.println(Thread.currentThread().getName()+"在买票"+"还剩下"+ticaketCount+"张票"); } } } }}
Demo测试类:
public class Demo { public static void main(String[] args) { Runnable ra=new Runnable(); //创建一个对象 三个线程 要是创建三个线程的话就是三百张票 Thread t1=new Thread(ra); Thread t2=new Thread(ra); Thread t3=new Thread(ra); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); }}注意:要是有两个线程对象,需要加入static关键字修饰同步方法:就是把synchronized关键字加到方法上 格式: 修饰符synchronized返回值类型方法名(方法参数){} 同步代码块和同步方法的区别 同步代码块锁住指定代码,同步方法是锁住方法中的所有代码 同步代码块可以指定锁对象,同步方法不能指定锁对象 同步方法的锁对象就是this 代码:
public class MyRunnable implements Runnable{ private static int ticaketCount=100; @Override public void run() { while (true){ if ("窗口一".equals(Thread.currentThread().getName())){ //同步方法 boolean b = synchronizedMethod(); if (b){ break; } }if ("窗口二".equals(Thread.currentThread().getName())){ //同步代码块 synchronized (MyRunnable.class){ if (ticaketCount==0){ //票买完了 break; }else { //Thread.currentThread().getName() 线程名称 //ticaketCount 票的数量 try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } ticaketCount--; System.out.println(Thread.currentThread().getName()+"在买票"+"还剩下"+ticaketCount+"张票"); } } } } } private synchronized boolean synchronizedMethod() { if (ticaketCount==0){ return true; }else { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } ticaketCount--; System.out.println(Thread.currentThread().getName()+"在买票"+"还剩下"+ticaketCount+"张票"); return false; } }}
Demo测试类:
public class Demo { public static void main(String[] args) { MyRunnable mr=new MyRunnable(); Thread t=new Thread(mr); Thread t2=new Thread(mr); t.setName("线程1"); t2.setName("线程2"); t.start(); t2.start(); }}同步静态方法:就是把synchronized关键字加到静态方法上 格式: 修饰符 static synchronized 返回值类型 方法名(方法参数){} 同步静态方法的锁是 类名.thisLock锁 JDK1.5之后提供了一个新的锁对象 void lock; 获得锁 void unlock;释放锁 Lock是接口不能被实例化,这里采用了它的实现类ReentrantLock来实例化 ReentrantLock的构造方法 ReentrantLocK():创建一个ReentrantLock的实例 代码改进:
public class Runnable implements java.lang.Runnable { //票的数量 private int ticaketCount=100; //private Object obj=new Object(); private ReentrantLock lock =new ReentrantLock(); @Override public void run() { while (true){ //锁对象是任意的 , 多个线程必须使用同一把锁 //synchronized (obj){ try { lock.lock(); if (ticaketCount==0){ //票买完了 break; }else { //Thread.currentThread().getName() 线程名称 //ticaketCount 票的数量 Thread.sleep(100); ticaketCount--; System.out.println(Thread.currentThread().getName()+"在买票"+"还剩下"+ticaketCount+"张票"); } } catch (InterruptedException e) { e.printStackTrace(); }finally { lock.unlock(); } // } } }}Demo测试类:
public class Demo { public static void main(String[] args) { Runnable ra=new Runnable(); //创建一个对象 三个线程 要是创建三个线程的话就是三百张票 Thread t1=new Thread(ra); Thread t2=new Thread(ra); Thread t3=new Thread(ra); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t1.start(); t2.start(); t3.start(); }}
死锁
线程死锁就是指两个或者多个线程相互持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行 代码:public class Test { public static void main(String[] args) { Object oa=new Object(); Object ob=new Object(); new Thread(()->{ while (true){ synchronized (oa){ synchronized (ob){ System.out.println("oa线程正在运行"); } } } }).start(); new Thread(()->{ while (true){ synchronized (ob){ synchronized (oa){ System.out.println("ob线程正在运行"); } } } }).start(); }}
转载地址:https://blog.csdn.net/weixin_50991263/article/details/123836497 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
表示我来过!
[***.240.166.169]2024年04月03日 04时45分45秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
欧洲计算机视觉国际会议ECCR20最新论文整理分享
2021-06-30
20年6月最新-《深度神经网络的高效处理技术综述》
2021-06-30
BiliBili 100+国际名校免费公开课整理分享
2021-06-30
清华大学计算机学科推荐学术会议和期刊列表
2021-06-30
【组队学习】【24期】Docker教程
2021-06-30
Datawhale组队学习周报(第010周)
2021-06-30
【直播】杨毅远:集成学习答疑直播之六 -- 幸福感预测案例实战
2021-06-30
如何使用Python的进度条?
2021-06-30
如何利用情感词典做中文文本的情感分析?
2021-06-30
【青少年编程】【Scratch】06 侦测模块
2021-06-30
【直播】李祖贤:集成学习答疑直播之八-- 集成知识点回顾与补充
2021-06-30
Datawhale组队学习周报(第013周)
2021-06-30
如何设置matplotlib中x,y坐标轴的位置?
2021-06-30
【第15周复盘】B站是个学习的网站
2021-06-30
黄家懿:河北高校邀请赛 -- 二手车交易价格预测决赛答辩
2021-06-30
如何利用pyecharts绘制酷炫的桑基图?
2021-06-30
王朝阳:河北高校邀请赛 -- 二手车交易价格预测决赛答辩
2021-06-30
Scratch等级考试(二级)模拟题
2021-06-30
如何在Jupyter Lab中显示pyecharts的图形?
2021-06-30
什么是Python之禅?
2021-06-30