多线程资源共享
2015-09-25 14:35
337 查看
一、线程的创建和启动
定义线程类实现Runnable接口:Thread myThread = new Thread(target) //target为Runnable接口类型
而 Runnable中只有一个方法:
public void run();用以定义线程运行体
Thread 类是一个具体的类,该类封装了线程的行为。要创建一个线程,程序员必须创建一个从 Thread 类导出的新类。程序员必须覆盖 Thread 的 run() 函数来完成有用的工作。用户并不直接调用此函数;而是必须调用 Thread 的 start() 函数,该函数再调用 run()。
class threadTest implements Runnable { public threadTest(String numberID) { this.numberID = numberID; } public void run() { for (int i = 0; i < 4; i++) { System.out.println(numberID + " is running " + i); } } public static void main(String[] args) { threadTest h1=new threadTest("线程A"); Thread demo= new Thread(h1); threadTest h2=new threadTest("线程B"); Thread demo1=new Thread(h2); demo.start(); demo1.start(); } private String numberID; }
二、线程状态装换
线程在它的生命周期中会处于各种不同的状态:新建、等待、就绪、运行、阻塞、死亡。
当调用线程start()方法时,线程进入就绪状态,Cpu分配时间片,线程进入运行状态,时间片结束,run()方法未执行完,线程进入阻塞状态。
线程转换详细过程可参见下图:
三、线程控制基本方法
由于java线程调度不是分时的,如果程序希望干预java虚拟机对线程的调度过程,从而明确地让一个线程给另外一个线程运行的机会,可以采用以下的方法进行干预:1. 调整各个线程的优先级,可用的方法有
getPriority() //获得线程的优先级数值
setPriority() //设置线程的优先级指数
2. 让处于运行状态的线程调用Thread.sleep(long time)方法 放弃CPU 进入阻塞状态
Thread.sleep() //静态方法,将当前线程睡眠指定毫秒数,sleep方法可能抛出InterruptedException异常。
3. 让处于运行状态的线程调用Thread.yield()方法让出CPU,当前线程进入就绪状态等待调度,这个只会对同优先级让步或更高优先级让步
4. 让处于运行状态的线程调用另一个线程的join()方法,调用某线程的该方法,将当前线程与该线程合并,当前运行的线程将转到阻塞状态,直至另一个线程运行结束,它才会转到就绪状态,从而有机会恢复运行。
5. 使用interrupt方法中断线程。
interrupt() //中断线程
四、多线程资源共享
多线程编程的一个重要原因是实现资源的共享,一个进程中的所有线程都会共享这个进程中的资源,当超过一个线程会同时修改同一个数据,或有修改有访问的话,就会产生同步问题,这时可以用以下几种方式解决:1.同步方法,用synchronized关键字修饰的方法
每一个java对象中有一个内置锁,如果方法使用了synchronized进行修饰的话,内置锁会保护整个方法,也就是在调用方法之前,需要、获得内置锁,否则就会处于阻塞状态,当然这个关键字也可以修饰静态方法,如果调用静态方法,就会锁住整个类实现同步。
public synchronized void balance(int money){ balance += money; }
其实:balance += money;
的执行是分3步运行的,读取变量balance的当前值,对当前值增加money,将新的值写入变量balance,在多线程中,有可能两个线程同时读取balance的值,这样就会少计算一次money的值。
2.使用特殊域变量实现同步
可以使用volatile关键字来确保多线程之间的变量读写的可见性,如:
private volatile int balance = 100;
将可能会被多线程访问到的变量使用关键字volatile设置为特殊域变量。volatile提供了一种免锁的机制,使用这个关键字修饰的域相当于告诉虚拟机,这个域可能会被其他的线程跟新,因此每次读取这个域的时候都需要重新计算,而不是使用寄存器中的值,这个关键字不会提供任何的原子操作,也不能用来修饰final类型的变量、
3.ThreadLoacal
在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
private static ThreadLocal<Integer> balance = new ThreadLocal<Integer>(){ protected Integer initialValue(){ return 100; } }
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响,最适合的是按线程多实例的情况.
相关文章推荐
- Android引用Library的若干问题(全都是坑啊,一定要注意了)
- 回到顶部按钮
- binbinyang---eclipse中show whitespace characters按钮编辑器中显示导致恶心的乱码
- Telnet访问邮件服务器
- 普及JSTL之核心标签库----基础文档
- Swift - 开关按钮(UISwitch)的用法
- Swift - 多行文本输入框(UITextView)的用法
- 文章标题
- 2. Rust的三板斧 安全,迅速,并发
- 如何通过网页提供iOS应用下载
- 转:苹果应用商店DNS修改加快下载速度
- Mysql时间戳
- lintcode-区间求和I-206
- ios开发之 获取APP版本号/跳转APPStore(下载页/评论页)
- AngularJs过滤器
- Swift - 文本输入框(UITextField)的用法
- 此纳税人登记号已用于同一期间的交易方(交易方类型为 XXX 且交易方名称为 xxxx)。
- 路由机制
- NOIP 2005 篝火晚会 COGS 112(只是用到置换的一个小概念而已)
- C#默认参数