分享Java如何实现线程同步
|
Java线程同步是保证多线程状态下安全访问竞争资源的一种编程手段,但线程的同步在Java多线程编程中算是一个比较难的难点,很多开发者甚至都不知道什么是竞争资源,也不知道时候需要进行线程同步,当然这是没有明确答案的,一些原则问题还是要考虑。
Java如何实现线程同步? 对于同步,在具体的Java代码中需要完成一下两个操作: 1、把竞争访问的资源标识为private; 2、同步哪些修改变量的代码,使用synchronized关键字同步方法或代码。 当然这不是唯一控制并发安全的途径。 synchronized 关键字使用说明 synchronized 只能标记非抽象的方法,不能标识成员变量。 为了演示同步方法的使用,构建了一个信用卡账户,起初信用额为100w,然后模拟透支、存款等多个操作。显然银行账户User对象是个竞争资源,而多个并发操作的是账户方法oper(int x),当然应该在此方法上加上同步,并将账户的余额设为私有变量,禁止直接访问。 01/**02* Java线程:线程的同步03*04* @author leizhimin 2009-11-4 11:23:3205*/06public class Test {07public static void main(String[] args) {08User u = new User("张三", 100);09MyThread t1 = new MyThread("线程A", u, 20);10MyThread t2 = new MyThread("线程B", u, -60);11MyThread t3 = new MyThread("线程C", u, -80);12MyThread t4 = new MyThread("线程D", u, -30);13MyThread t5 = new MyThread("线程E", u, 32);14MyThread t6 = new MyThread("线程F", u, 21);15t1.start();16t2.start();17t3.start();18t4.start();19t5.start();20t6.start();21}22}23class MyThread extends Thread {24private User u;25private int y = 0;26MyThread(String name, User u, int y) {27super(name);28this.u = u;29this.y = y;30}31public void run() {32u.oper(y);33}34}35class User {36private String code;37private int cash;38User(String code, int cash) {39this.code = code;40this.cash = cash;41}42public String getCode() {43return code;44}45public void setCode(String code) {46this.code = code;47}48/**49* 业务方法50* @param x 添加x万元51*/52public synchronized void oper(int x) {53try {54Thread.sleep(10L);55this.cash = x;56System.out.println(Thread.currentThread().getName() "运行结束,增加“" x "”,当前用户账户余额为:" cash);57Thread.sleep(10L);58} catch (InterruptedException e) {59e.printStackTrace();60}61}62@Override63public String toString() {64return "User{" 65"code='" code ''' 66", cash=" cash 67'}';68}69}复制代码/*** Java线程:线程的同步** @author leizhimin 2009-11-4 11:23:32*/public class Test {public static void main(String[] args) {User u = new User("张三", 100);MyThread t1 = new MyThread("线程A", u, 20);MyThread t2 = new MyThread("线程B", u, -60);MyThread t3 = new MyThread("线程C", u, -80);MyThread t4 = new MyThread("线程D", u, -30);MyThread t5 = new MyThread("线程E", u, 32);MyThread t6 = new MyThread("线程F", u, 21);t1.start();t2.start();t3.start();t4.start();t5.start();t6.start();}}class MyThread extends Thread {private User u;private int y = 0;MyThread(String name, User u, int y) {super(name);this.u = u;this.y = y;}public void run() {u.oper(y);}}class User {private String code;private int cash;User(String code, int cash) {this.code = code;this.cash = cash;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}/*** 业务方法* @param x 添加x万元*/public synchronized void oper(int x) {try {Thread.sleep(10L);this.cash = x;System.out.println(Thread.currentThread().getName() "运行结束,增加“" x "”,当前用户账户余额为:" cash);Thread.sleep(10L);} catch (InterruptedException e) {e.printStackTrace();}}@Overridepublic String toString() {return "User{" "code='" code ''' ", cash=" cash '}';}} 输出结果: 01线程A运行结束,增加“20”,当前用户账户余额为:12002线程F运行结束,增加“21”,当前用户账户余额为:14103线程E运行结束,增加“32”,当前用户账户余额为:17304线程C运行结束,增加“-80”,当前用户账户余额为:9305线程B运行结束,增加“-60”,当前用户账户余额为:3306线程D运行结束,增加“-30”,当前用户账户余额为:307Process finished with exit code 0复制代码线程A运行结束,增加“20”,当前用户账户余额为:120线程F运行结束,增加“21”,当前用户账户余额为:141线程E运行结束,增加“32”,当前用户账户余额为:173线程C运行结束,增加“-80”,当前用户账户余额为:93线程B运行结束,增加“-60”,当前用户账户余额为:33线程D运行结束,增加“-30”,当前用户账户余额为:3Process finished with exit code 0 反面教材,不同步的情况,也就是去掉oper(int x)方法的synchronized修饰符,然后运行程序,结果如下: 01线程A运行结束,增加“20”,当前用户账户余额为:6102线程D运行结束,增加“-30”,当前用户账户余额为:6303线程B运行结束,增加“-60”,当前用户账户余额为:304线程F运行结束,增加“21”,当前用户账户余额为:6105线程E运行结束,增加“32”,当前用户账户余额为:9306线程C运行结束,增加“-80”,当前用户账户余额为:6107Process finished with exit code 0复制代码线程A运行结束,增加“20”,当前用户账户余额为:61线程D运行结束,增加“-30”,当前用户账户余额为:63线程B运行结束,增加“-60”,当前用户账户余额为:3线程F运行结束,增加“21”,当前用户账户余额为:61线程E运行结束,增加“32”,当前用户账户余额为:93线程C运行结束,增加“-80”,当前用户账户余额为:61Process finished with exit code 0 很显然,上面的结果是错误的,导致错误的原因是多个线程并发访问了竞争资源u,并对u的属性做了改动。 可见同步的重要性。 注意: 通过前文可知,线程退出同步方法时将释放掉方法所属对象的锁,但还应该注意的是,同步方法中还可以使用特定的方法对线程进行调度。这些方法来自于java.lang.Object类。 01void notify()02唤醒在此对象监视器上等待的单个线程。03void notifyAll()04唤醒在此对象监视器上等待的所有线程。05void wait()06导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。07void wait(long timeout)08导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。09void wait(long timeout, int nanos)10导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。复制代码void notify()唤醒在此对象监视器上等待的单个线程。void notifyAll()唤醒在此对象监视器上等待的所有线程。void wait()导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。void wait(long timeout)导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。void wait(long timeout, int nanos)导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。 以上步骤便是Java多线程编程中的线程同步用法,为了清楚了解这部分概念,笔者还展示了反面教程的使用,避免用户走更多的弯路。 |
相关文章
热销商品
天熊猫T-15收音机老人专用全波段新款半导体老年人老式调频短波便携
熊猫T-15收音机老人专用全波段新款半导体老年人老式调频短波便携
¥125 领券购买
天熊猫T-37全波段老人新款收音机专用老年老式复古怀旧充电款半导体
熊猫T-37全波段老人新款收音机专用老年老式复古怀旧充电款半导体
¥98 领券购买
天索贝纳英语四六级听力收音机大学考试专用FM调频专八4级6级接收机
索贝纳英语四六级听力收音机大学考试专用FM调频专八4级6级接收机
¥29.9 领券购买
天喜马拉雅播放器新款收音机老人专用充电款2026年陪伴机新年礼物
喜马拉雅播放器新款收音机老人专用充电款2026年陪伴机新年礼物
¥649 领券购买
天【羊毛】雅戈尔秋季官方新款TR西裤商务通勤男士中青年高级长裤子
【羊毛】雅戈尔秋季官方新款TR西裤商务通勤男士中青年高级长裤子
¥389 领券购买
淘【林秋楠同款】haonanhuang立褶微喇抗皱弹力西裤男女
【林秋楠同款】haonanhuang立褶微喇抗皱弹力西裤男女
¥289 领券购买
淘【1930s 600g重50羊毛】CULTUM好莱坞裤免熨烫复古双褶直筒西裤男
【1930s 600g重50羊毛】CULTUM好莱坞裤免熨烫复古双褶直筒西裤男
¥439 领券购买
天【新香首发】佩枪朱丽叶朱丽叶女士香水礼盒持久留香花果香调正品
【新香首发】佩枪朱丽叶朱丽叶女士香水礼盒持久留香花果香调正品
¥781 领券购买
淘adidas/阿迪达斯 Grand Court Alpha 减震透气防滑耐磨网球鞋板鞋
adidas/阿迪达斯 Grand Court Alpha 减震透气防滑耐磨网球鞋板鞋
¥318 领券购买
淘FILA斐乐儿童轻薄羽绒服2025冬新款童装小童网球上衣连帽宝宝外套
FILA斐乐儿童轻薄羽绒服2025冬新款童装小童网球上衣连帽宝宝外套
¥591 领券购买
天恒源祥女士纯棉抗菌舒适吸汗透气夏季运动休闲百搭中筒袜黑白棉袜
恒源祥女士纯棉抗菌舒适吸汗透气夏季运动休闲百搭中筒袜黑白棉袜
¥29.9 领券购买
天361°男袜春秋薄款网眼透气吸汗棉袜男士抗菌防臭休闲运动短筒袜
361°男袜春秋薄款网眼透气吸汗棉袜男士抗菌防臭休闲运动短筒袜
¥29.9 领券购买
天361男袜正品春夏男款运动棉袜吸汗透气跑步袜除臭休闲商务中筒袜
361男袜正品春夏男款运动棉袜吸汗透气跑步袜除臭休闲商务中筒袜
¥24.9 领券购买
天361正品男袜春夏薄款男士透气防臭棉袜吸汗耐磨运动休闲商务短袜
361正品男袜春夏薄款男士透气防臭棉袜吸汗耐磨运动休闲商务短袜
¥29.9 领券购买
淘BlessedFolks极简个性弹力减震防磨球类运动休闲跑步男士中筒棉袜
BlessedFolks极简个性弹力减震防磨球类运动休闲跑步男士中筒棉袜
¥33.4 领券购买
天老北京布鞋女2026新款春秋防滑一脚蹬妈妈单鞋软底舒适酒店工作鞋
老北京布鞋女2026新款春秋防滑一脚蹬妈妈单鞋软底舒适酒店工作鞋
¥58.5 领券购买

