《java多线程(附示例代码)》由会员分享,可在线阅读,更多相关《java多线程(附示例代码)(30页珍藏版)》请在金锄头文库上搜索。
1、JAVA 多线程,概念 线程应用 线程状态 线程属性 线程同步 Q & A,概念,多任务系统 进程 线程,示例,单线程程序 多线程程序,线程应用 java.lang.Thread,使用线程的两种常用方式 实现Runnable接口的run方法 class MyRunnable implements Runnablepublic void run()System.out.println(“hello“); MyRunnable r = new MyRunnable(); Thread thread = new Thread(r); thread.start();,线程应用 java.lang.Th
2、read,2. 继承Thread,覆盖run方法(不推荐) class MyThread extends Threadpublic void run() System.out.println(“MyThread.run is running!“); MyThread t = new MyThread(); t.start(); / Never call t.run(),线程状态 Thread.State,NEW(新生)至今尚未启动的线程处于这种状态。 RUNNABLE(可运行)正在 Java 虚拟机中执行的线程处于这种状态。 BLOCKED(被阻塞)受阻塞并等待某个监视器锁的线程处于这种状态。
3、 WAITING(等待)无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。 TIMED_WAITING(计时等待)等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态。 TERMINATED(被终止)已退出的线程处于这种状态。,线程状态,中断线程,Thread.interrupt() 该方法被调用时,线程的中断状态(boolean)将被置位。 线程应不时的检查这个中断状态标志,以判断线程是否被中断,进一步决定如何响应中断。,中断线程,Thread.interrupt() Public void run()trywhile(!Thread.currentThread().is
4、Interrupted() & more condiiton to check) /线程任务代码catch (InterruptedException e)/ 线程处于sleep或wait被中断,会导致该 /异常产生finally/清理工作/退出run方法,结束该线程 ,线程属性,线程优先级 守护线程 未捕获异常处理器,线程优先级,线程优先级高度依赖于操作系统 (1)windows有7个优先级别,一些JAVA线程优先级将映射至操作系统优先级 (2)在Sun为linux提供的JVM中,线程优先级被忽略 请勿将程序构建为功能的正确性依赖于线程优先级(例:调度框架),守护线程,作用:为其他线程提供服
5、务。例: (1)计时线程定时发送时间信号给其他线程; (2)定期清空过时的缓存内容的线程 当只剩下守护线程时,虚拟机就会退出 设置方式 thread.setDaemon(true),未捕获异常处理器,线程Run方法不能抛出任何被检测的异常 不被检测的异常会导致线程终止。线程在死亡前,异常会被传递至一个用于未捕获异常的处理器中。 Thread.UncaughtExceptionHandler thread.setDefaultUncaughtExceptionHandler 如果不为独立的线程设置处理器,则此时的处理器为该线程的ThreadGroup对象,线程组 ThreadGroup,线程组是
6、一个可以统一管理的线程集合 ThreadGroup实现了Thread.UncaughtExceptionHandler接口,它的uncaughtException方法执行以下操作: (1)如果该线程组有父线程组,那么父线程组的uncaughtException方法被调用。 (2)否则,如果Thread.getDefaultExceptionHandler方法返回一个非空值,则调用该处理器。 (3)否则,如果Throwable是ThreadDeath的一个实例,则不作任何处理。 (4)否则,线程的名字以及Throwable的栈踪迹被速出到System.err上。,线程组 ThreadGroup,
7、从JAVA SE 5.0起引入了更好的特性用于线程集合(java.util.concurrent.*)的操作,请不要在自己的程序中使用线程组。,线程同步,竞争条件(Race Condition) 实现线程同步的方式 Volatile域 死锁,竞争条件,竞争条件(Race Condition)在大多数实际的多线程应用中,根据线程的访问数据的次序,被多个线程共享访问、修改的对象可能会出现错误的情况。 示例模拟一有若干账户的银行,随机地生成在这些账户之间转移钱款的交易。每个账户有一个执行交易的线程。每一个笔交易中,会从线程所服务的账户中随机转移一定数目的钱款到另一个随机账户。(银行总钱数保持不变),
8、竞争条件,示例分析 假定两个线程同时执行指令(to值相同) Accountsto += amount; 这句不是原子操作,该指令实际可能被拆分成(可用命令javap c v Class Name反编译查看字节码): (1)将accountsto加载至寄存器(CPU) (2)增加amount (3)将结果写回accountsto 假定线程1执行步骤1、2,然后被剥夺运行权。 此时线程2被唤醒并执行完以上3个步骤(修改 同一个accountto)。然后线程1被唤醒继续完 成其步骤3。,实现线程同步的方式,锁对象 条件对象 synchronized关键字,锁对象,java.util.concurre
9、nt.locks.ReentrantLock private Lock bankLock=new ReentrantLock(); bankLock.lock(); Try/critical section FinallybankLock.unlock(); ,条件对象,又称条件变量conditional variable 通常,线程获得锁进入临界区后,却发现在某一条件满足之后才能继续执行。 一个锁对象可以有一个或多个相关的条件对象(lock.newCondition(),条件对象,private Lock bankLock = new ReentrantLock(); private Con
10、dition sufficientFunds = bankLock.newCondition(); bankLock.lock(); Trywhile(accountsfrom amount)sufficientFunds.await();/transfer fundssufficientFunds.signalAll(); FinallybankLock.unlock(); ,synchronized关键字,public synchronized void method()/method body 功能上等价于Lock lock = new ReentrantLock(); Public v
11、oid method()this.lock.lock();try/method bodyfinallythis.lock.unlock(); ,synchronized关键字,1. public synchronized void method()/method body 2. public synchronized static void method()/method body 3. Object obj = new Object(); public void method()synchronized(obj)/method body ,Volatile,多处理器的计算机能够暂时在寄存器或
12、本地内存缓存区中保存内存的值。结果是,运行在不同处理器上的线程可能在同一个内存位置取到不同的值。 Volatile关键字为实例域的同步访问提供了一种免锁机制。可被看做是一种“程度较轻的 synchronized” 具有 synchronized 的可见性特性,但是不具备原子特性,Volatile,锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility)。互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获
13、得该锁的另一个线程是可见的 结合使用 volatile 和 synchronized 实现 “开销较低的读写锁” public class CheesyCounter private volatile int value;public int getValue() return value; public synchronized int increment() return value+; synchronized 确保增量操作是原子的,并使用 volatile 保证当前结果的可见性,死锁,当两个或两个以上的线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推
14、进下去。 形成死锁的四个必要条件 1. 互斥使用(资源独占) 一个资源每次只能给一个线程使用 2. 不可强占(不可剥夺) 资源申请者不能强行的从资源占有者手中夺取资源,资源只能由占有者自愿释放 3. 请求和保持一个线程在申请新的资源的同时保持对原有资源的占有 4. 循环等待 存在一个线程等待队列 T1 , T2 , , Tn, 其中T1等待T2占有的资源,T2等待T3占有的资源,Tn等待T1占有的资源,形成一个线程等待环路,死锁检测,jconsole,参考资料,JAVA核心技术 Java 理论与实践: JDK 5.0 中更灵活、更具可伸缩性的锁定机制( http:/ ) Java 理论与实践: 正确使用 Volatile 变量( http:/ ),Q & A,Thank you!,