一. Java多线程安全问题,模拟银行存款
/** * *银行账户对象,存取款操作 * */ public class Account { String name; float amount; public Account(String name, float amount) { this.name = name; this.amount = amount; } // 存款 public void deposit(float amt) { float tmp = amount; tmp += amt; try { Thread.sleep(100);//模拟其它处理所需要的时间,比如刷新数据库等 } catch (InterruptedException e) { // ignore } amount = tmp; } // 取款 public void withdraw(float amt) { float tmp = amount; tmp -= amt; try { Thread.sleep(100);//模拟其它处理所需要的时间,比如刷新数据库等 } catch (InterruptedException e) { // ignore } amount = tmp; } public float getBalance() { return amount; } }
/** * * 多线程模拟银行存取款,如果没有采取同步,就会出现多线程安全问题, * 则最终的银行账户会出现金额不一致的情况。 * */ public class AccountTest { private static int NUM_OF_THREAD = 1000; static Thread[] threads = new Thread[NUM_OF_THREAD]; public static void main(String[] args){ final Account acc = new Account("John", 1000.0f); for (int i = 0; i< NUM_OF_THREAD; i++) { threads[i] = new Thread(new Runnable() { public void run() { acc.deposit(100.0f); acc.withdraw(100.0f); } }); threads[i].start(); } for (int i=0; i<NUM_OF_THREAD; i++){ try { threads[i].join(); //等待所有线程运行结束 } catch (InterruptedException e) { // ignore } } System.out.println("Finally, John's balance is:" + acc.getBalance()); } }
二、Java多线程之synchronized
/** * * synchronized中同步的对象必须是多线程中访问的同一个对象,否则达不到同步效果, * 也可用synchronized(this)代表当前对象。 * 如果为synchronized(name)则达不到同步效果。 * */ public class Foo extends Thread { private int val; // 通过对公共对象静态变量加锁 private static Object lock = new Object(); public Foo(int v) { val = v; } // 交叉输出(1,3) public synchronized void printVal1(int v) { while(true){ System.out.println(v); } } // 类同步,实现printVal是断面,输出只能是1或者只能是3而不能是两者同时出现 public void printVal2(int v) { synchronized(Foo.class) { while(true){ System.out.println(v); } } } // 同步的一般原理是应该尽量减小同步的粒度以到达更好的性能,比类同步(printVal2)效果更忧 public void printVal3(int v) { synchronized(lock) { while(true){ System.out.println(v); } } } public void run() { // printVal1(val); // printVal2(val); printVal3(val); } }
public class FooTest { public static void main(String args[]){ Foo f1 = new Foo(1); f1.start(); Foo f2 = new Foo(3); f2.start(); } }
三. Java多线程之ThreadLocal
事例一:
/** * *在Java的多线程编程中,为保证多个线程对共享变量的安全访问,通常会使用synchronized来保证同一时刻 *只有一个线程对共享变量进行操作。但在有些情况下,synchronized不能保证多线程对共享变量的正确读写。 *对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间” *的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量, *因此可以同时访问而互不影响。 */ public class QuerySvc { private String sql; private static ThreadLocal<String> sqlHolder = new ThreadLocal<String>(); public QuerySvc() { } /** * 从运行结果可以看出sql变量中值不能保证在execute中值和set设置的值一样, 在web应用中就表现 * 为一个用户查询的结果不是自己的查询条件返回的结果,而是另一个用户查询条件的结果; * 而ThreadLocal中的值总是和set中设置的值一样,这样通过使用ThreadLocal获得了线程安全性。 */ public void execute() { System.out.println("Thread " + Thread.currentThread().getId() + " Sql is " + sql); System.out.println("Thread " + Thread.currentThread().getId() + " Thread Local variable Sql is " + sqlHolder.get()); } public String getSql() { return sql; } public void setSql(String sql) { this.sql = sql; sqlHolder.set(sql); } private static class Work extends Thread{ private QuerySvc querySvc; private String sql; public Work(QuerySvc querySvc,String sql){ this.querySvc = querySvc; this.sql = sql; } public void run() { querySvc.setSql(sql); querySvc.execute(); } } public static void main(String args[]){ QuerySvc querySrc = new QuerySvc(); for(int k=0;k<10;k++){ String sql = "Select * from table where id =" + k; new Work(querySrc,sql).start(); } } }
事例二:
/** * 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本, * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 * 如果要保存多个线程变量,可定义多个ThreadLocal变量, * 或者将多个变量封装到一个对象中,将整个对象保存到ThreadLocal变量。 * */ public class SequenceNumber { private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){ public Integer initialValue(){ return 0; } }; public Integer getNextNum(){ seqNum.set(seqNum.get()+1); return seqNum.get(); } // 测试方法 public static void main(String args[]){ SequenceNumber sn = new SequenceNumber(); // 3个线程共享sn,各自产生序列号 TestClient t1 = new TestClient(sn); TestClient t2 = new TestClient(sn); TestClient t3 = new TestClient(sn); t1.start(); t2.start(); t3.start(); } // 内部静态线程类 private static class TestClient extends Thread{ private SequenceNumber sn; public TestClient(SequenceNumber sn) { this. sn = sn; } public void run() { //每个线程打出3个序列值 for (int i = 0; i < 3; i++) { System.out.println("thread["+Thread.currentThread().getName()+ "] sn["+sn.getNextNum()+"]"); } } } }
相关推荐
描述java多线程的例子,可供进一步学习多线程的人参考
这是Java多线程编程实例一书的全部随书源码,这本书是很早的JAVA多线程编程指导书,虽然很老但是很经典,直到现在还很热,很有参考价值。
java 多线程实例,多线程参考资料!
java多线程实例 简单的实现机制 源码参考 自己写的
《Java多线程编程实战指南(核心篇)》以基本概念、原理与方法为主线,辅以丰富的实战案例和生活化实例,并从Java虚拟机、操作系统和硬件多个层次与角度出发,循序渐进、系统地介绍Java平台下的多线程编程核心技术及...
(注意,本资源附带书中源代码可供参考) 多线程与并发处理是程序设计好坏优劣的重要课题,本书通过浅显易懂的文字与实例来介绍Java线程相关的设计模式概念,并且通过实际的Java程序范例和 UML图示来一一解说,书中...
本文给大家介绍java多线程实例,对java多线程知识感兴趣的朋友参考下吧
java 多线程下载实例,供需要参考的童鞋学习。
java Runnable线程简单实例。简单实用,可用可参考;多用多理解;线程可用用在很多场景,java程序猿必备技能
一个线程实例,可以下载下来参考参考,方便学习进步嘛!
用Java编写的多线程下载 实例,Myeclipse中完整工程。 需要的朋友可以参考一下!
主要介绍了java多线程编程实例,分享了几则多线程的实例代码,具有一定参考价值,加深多线程编程的理解还是很有帮助的,需要的朋友可以参考下。
主要介绍了Java多线程并发执行demo代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要介绍了JAVA 多线程爬虫实例详解的相关资料,需要的朋友可以参考下
主要介绍了Java多线程 实例解析,需要的朋友可以参考下
大学学习Java的时候做的一个作业,JAVA多线程和C++中的使用方法有所不同,花了很久才作出这个DEMO,不过,从此以后,就可以编写大规模JAVA程序了,希望是入门学习的一个好的参考。
java多线程结合界面开发实例(原创)财务管理系统源代码和效果图[参考].pdf
主要介绍了JAVA多线程编程,结合实例形式总结分析了多线程、锁、线程池等相关原理及使用技巧,需要的朋友可以参考下
编写程序创建Storage类的实例,并创建一个Counter对象和Printer对象操作此实例。 实验步骤: (1)、创建三个类Counter, Printer,Storage (2)、创建TestCounter类,在该类中定义main函数,在main函数中定义Storage...
主要为大家详细介绍了Java多线程下载文件的实例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下