Java线程:线程的同步-同步方法

简介:
线程的同步是保证多线程安全访问竞争资源的一种手段。
线程的同步是Java多线程编程的难点,往往开发者搞不清楚什么是竞争资源、什么时候需要考虑同步,怎么同步等等问题,当然,这些问题没有很明确的答案,但有些原则问题需要考虑,是否有竞争资源被同时改动的问题?
 
在本文之前,请参阅《 Java线程:线程的同步与锁》,本文是在此基础上所写的。
 
对于同步,在具体的Java代码中需要完成一下两个操作:
把竞争访问的资源标识为private;
同步哪些修改变量的代码,使用synchronized关键字同步方法或代码。
当然这不是唯一控制并发安全的途径。
 
synchronized关键字使用说明
synchronized只能标记非抽象的方法,不能标识成员变量。
 
为了演示同步方法的使用,构建了一个信用卡账户,起初信用额为100w,然后模拟透支、存款等多个操作。显然银行账户User对象是个竞争资源,而多个并发操作的是账户方法oper(int x),当然应该在此方法上加上同步,并将账户的余额设为私有变量,禁止直接访问。
 
 
/** 
* 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(); 
                } 
        } 

        @Override 
         public String toString() { 
                 return  "User{" + 
                                 "code='" + code + '\'' + 
                                 ", cash=" + cash + 
                                '}'; 
        } 
}
 
输出结果:
线程A运行结束,增加“20”,当前用户账户余额为:120 
线程F运行结束,增加“21”,当前用户账户余额为:141 
线程E运行结束,增加“32”,当前用户账户余额为:173 
线程C运行结束,增加“-80”,当前用户账户余额为:93 
线程B运行结束,增加“-60”,当前用户账户余额为:33 
线程D运行结束,增加“-30”,当前用户账户余额为:3 

Process finished with exit code 0
 
 
反面教材,不同步的情况,也就是去掉oper(int x)方法的synchronized修饰符,然后运行程序,结果如下:
线程A运行结束,增加“20”,当前用户账户余额为:61 
线程D运行结束,增加“-30”,当前用户账户余额为:63 
线程B运行结束,增加“-60”,当前用户账户余额为:3 
线程F运行结束,增加“21”,当前用户账户余额为:61 
线程E运行结束,增加“32”,当前用户账户余额为:93 
线程C运行结束,增加“-80”,当前用户账户余额为:61 

Process finished with exit code 0
 
很显然,上面的结果是错误的,导致错误的原因是多个线程并发访问了竞争资源u,并对u的属性做了改动。
 
可见同步的重要性。
 
 
注意:
通过前文可知,线程退出同步方法时将释放掉方法所属对象的锁,但还应该注意的是,同步方法中还可以使用特定的方法对线程进行调度。这些方法来自于java.lang.Object类。
 
void notify()    
                    唤醒在此对象监视器上等待的单个线程。    
void notifyAll()    
                    唤醒在此对象监视器上等待的所有线程。    
void wait()    
                    导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。    
void wait( long timeout)    
                    导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。    
void wait( long timeout,  int nanos)    
                    导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
 
结合以上方法,处理多线程同步与互斥问题非常重要,著名的生产者-消费者例子就是一个经典的例子,任何语言多线程必学的例子。


本文转自 leizhimin 51CTO博客,原文链接:http://blog.51cto.com/lavasoft/221914,如需转载请自行联系原作者
相关文章
|
6天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
37 6
|
19天前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
15天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
15天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
40 3
|
16天前
|
监控 Java 开发者
深入理解Java中的线程池实现原理及其性能优化####
本文旨在揭示Java中线程池的核心工作机制,通过剖析其背后的设计思想与实现细节,为读者提供一份详尽的线程池性能优化指南。不同于传统的技术教程,本文将采用一种互动式探索的方式,带领大家从理论到实践,逐步揭开线程池高效管理线程资源的奥秘。无论你是Java并发编程的初学者,还是寻求性能调优技巧的资深开发者,都能在本文中找到有价值的内容。 ####
|
21天前
|
缓存 Java 开发者
Java多线程并发编程:同步机制与实践应用
本文深入探讨Java多线程中的同步机制,分析了多线程并发带来的数据不一致等问题,详细介绍了`synchronized`关键字、`ReentrantLock`显式锁及`ReentrantReadWriteLock`读写锁的应用,结合代码示例展示了如何有效解决竞态条件,提升程序性能与稳定性。
77 6
|
19天前
|
监控 Java 数据库连接
Java线程管理:守护线程与用户线程的区分与应用
在Java多线程编程中,线程可以分为守护线程(Daemon Thread)和用户线程(User Thread)。这两种线程在行为和用途上有着明显的区别,了解它们的差异对于编写高效、稳定的并发程序至关重要。
28 2
|
19天前
|
监控 Java 开发者
Java线程管理:守护线程与本地线程的深入剖析
在Java编程语言中,线程是程序执行的最小单元,它们可以并行执行以提高程序的效率和响应性。Java提供了两种特殊的线程类型:守护线程和本地线程。本文将深入探讨这两种线程的区别,并探讨它们在实际开发中的应用。
27 1
|
21天前
|
安全 Java 开发者
Java中的多线程编程:从基础到实践
本文深入探讨了Java多线程编程的核心概念和实践技巧,旨在帮助读者理解多线程的工作原理,掌握线程的创建、管理和同步机制。通过具体示例和最佳实践,本文展示了如何在Java应用中有效地利用多线程技术,提高程序性能和响应速度。
54 1
|
安全 Java 容器
Java并发编程 - 线程不安全类 & 同步/并发容器之简介
Java并发编程 - 线程不安全类 & 同步/并发容器之简介
120 0
Java并发编程 - 线程不安全类 & 同步/并发容器之简介
下一篇
DataWorks