6.11Java多线程、并发、同步、synchronized方法
2021/6/12 14:26:10
本文主要是介绍6.11Java多线程、并发、同步、synchronized方法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
6.11Java多线程、并发、同步、synchronized方法
摸索前进
package iostudy.synchro; /** * 多线程并发、同步保证数据准确性,效率尽可能高和好 * 线程安全: * 1、在并发池保证数据的准确性 * 2、同时保证效率尽可能高 * synchronized * 1、同步方法 * 2、同步块 * @since JDK 1.8 * @date 2021/6/11 * @author Lucfier */ public class SynTestNo1 { public static void main(String[] args) { /*创建资源类对象*/ SafeWeb12306 safeWeb12306 = new SafeWeb12306(); /*多个线程*/ new Thread(safeWeb12306, "fe斯特").start(); new Thread(safeWeb12306, "赛肯").start(); new Thread(safeWeb12306, "瑟得").start(); } } /** * 创建一个资源类,测试同步方法 */ class SafeWeb12306 implements Runnable{ /*票数*/ private int ticketNums = 99; /*设置开关*/ private boolean flag = true; /*重写run方法--->多线程执行入口*/ @Override public void run(){ while (flag){ /*在下面写线程的具体执行方法*/ test(); } } /** * 封装一个线程内部具体方法类 */ public synchronized void test(){ /*判断资源数、改变开关、结束方法*/ //每次方法一开始就执行判断 if (ticketNums<0){ /*改变开关状态*/ flag = false; /*结束方法*/ return; } /*模拟延时*/ try { /*线程携带数据锁休眠*/ Thread.sleep(200); }catch (InterruptedException e){ System.out.println(e.getMessage()); e.printStackTrace(); } /*打印当前线程对象信息--->获取当前线程方法*/ System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--); } }
之前出现负数资源的原因
-
最后一位资源为1
-
三个线程同时访问该资源(A,B,C)
-
B线程先运行,但是B不<=0,所以进行延时等待。B没有修改数据
-
此时A和C也进入线程体。此时B刚好修改数据而A和C访问到的资源数还是1
出现线程访问到相同资源数的原因
-
每个线程都有一个工作空间与主存交互
-
线程会round(加载)、store(存储)
-
当B线程没有将工作空间的修改数据返回主存的时候A、C线程也对主存的数据拷贝了一份
-
所以还是原来的资源数而不是更新后的资源数
这样就实现了同步,(线程大概率按顺序访问)
synchronized方法实例
package iostudy.synchro; /** * 多线程并发、同步保证数据准确性,效率尽可能高和好 * 线程安全: * 1、在并发池保证数据的准确性 * 2、同时保证效率尽可能高 * synchronized * 1、同步方法 * 2、同步块 * @since JDK 1.8 * @date 2021/6/11 * @author Lucfier */ public class SynTestNo1 { public static void main(String[] args) { /*创建资源类对象*/ SafeWeb12306 safeWeb12306 = new SafeWeb12306(); /*多个线程*/ new Thread(safeWeb12306, "fe斯特").start(); new Thread(safeWeb12306, "赛肯").start(); new Thread(safeWeb12306, "瑟得").start(); } } /** * 创建一个资源类,测试同步方法 */ class SafeWeb12306 implements Runnable{ /*票数*/ private int ticketNums = 1000; /*设置开关*/ private boolean flag = true; /*重写run方法--->多线程执行入口*/ @Override public void run(){ while (flag){ /*模拟延时*/ try { /*线程携带数据锁休眠*/ Thread.sleep(200); }catch (InterruptedException e){ System.out.println(e.getMessage()); e.printStackTrace(); } /*在下面写线程的具体执行方法*/ test(); } } /** * 封装一个线程内部具体方法类 */ public synchronized void test(){ /*判断资源数、改变开关、结束方法*/ //每次方法一开始就执行判断 if (ticketNums<0){ /*改变开关状态*/ flag = false; /*结束方法*/ return; } /*打印当前线程对象信息--->获取当前线程方法*/ System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--); } /* 1、该资源的锁操作了两个属性 1、ticketNums 2、flag 该方法是成员方法,操作的都是对象(this)SafeWeb12306--->锁的是对象 方法当中的资源必须是必须是对象的资源才能使用,非该对象的资源无法锁住 使用方法的时候判断对象是否能使用,有了锁就无法使用对象--->锁了对象的资源(方法当中都是与对象相关的资源。如果不是就可能是锁失败了) */ }
synchronized锁定目标不对(锁定对象不对),导致锁定失败
AccountTest类:
package iostudy.synchro; /** * 创建一个账户类--->资源类 * @since JDK 1.8 * @date 2021/6/10 * @author Lucifer */ public class AccountTest { /*定义资源属性*/ int money; //金额 String name; //名称字符串 /*创建构造器*/ public AccountTest(int money, String name) { this.money = money; this.name = name; } }
锁定错误的线程同步类:
package iostudy.synchro; public class SynTestNo2 { /*定义资源属性*/ int money; //金额 String name; //名称字符串 public static void main(String[] args) { AccountTest accountTest = new AccountTest(100, "money"); SafeDrawing you = new SafeDrawing(accountTest, 80, "Lucifer"); SafeDrawing she = new SafeDrawing(accountTest, 90, "JunkingBoy"); you.start(); she.start(); } /*创建构造器*/ public SynTestNo2(int money, String name) { this.money = money; this.name = name; } } /** * 模拟提款机提款类--->多线程 * @since JDK 1.8 * @date 2021/6/10 * @author Lucifer */ class SafeDrawing extends Thread{ /*创建实现类对象--->面向对象的思想*/ AccountTest accountTest; //取出的账户 int drawingMoney; //取出的钱数 int pocketTotal; //取出的钱的总数 /*创建构造器,将属性定义为参数*/ public SafeDrawing(AccountTest accountTest, int drawingMoney, String name) { super(name); //线程的名称 this.accountTest = accountTest; this.drawingMoney = drawingMoney; } /*重写run方法--->线程的具体实现*/ @Override public void run() { test(); } //目标锁定不对,锁定失败 /* 这里不是锁定this,而应该锁定account */ public synchronized void test(){ /*在存钱和取钱的时候加入条件*/ if (accountTest.money-drawingMoney<0){ /*结束方法*/ return; } /*模拟取款的网络延迟*/ try { Thread.sleep(1000); }catch (InterruptedException e){ System.out.println(e.getMessage()); e.printStackTrace(); } /* 理论上说加了判断就会控制结果 但是实际上不会,这个需要对资源+锁实现控制的效果 */ /*账户的金额-取出的金额*/ accountTest.money -= drawingMoney; /*口袋中的金额+取出的钱*/ pocketTotal += drawingMoney; /*因为继承了父类所以可以直接用this--->获取线程的名称*/ System.out.println(this.getName() + "--->账户余额为:" + accountTest.money); System.out.println(this.getName() + "--->身上余额为:" + pocketTotal); } /* 该方法的this是取款机的this,应该锁住的资源是AccountTest类的对象 */ }
这篇关于6.11Java多线程、并发、同步、synchronized方法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-27数据结构与算法面试题详解及练习
- 2024-12-27网络请求面试题详解与实战
- 2024-12-27数据结构和算法面试真题详解与实战教程
- 2024-12-27网络请求面试真题解析与实战教程
- 2024-12-27数据结构和算法大厂面试真题详解与实战指南
- 2024-12-27TS大厂面试真题解析与应对策略
- 2024-12-27TS大厂面试真题详解与解析
- 2024-12-27网站安全入门:如何识别和修复漏洞
- 2024-12-27SQL注入基础教程
- 2024-12-27初学者指南:理解和修复跨域漏洞