目录
线程 (下)
4. 线程同步-synchronized
The Java programming language provides two basic synchronization idioms: synchronized methods and synchronized statementsJava编程语言提供了两种基本的同步习惯用法:同步方法和同步代码块
同步方法语法
访问修饰符 synchronized 返回值类型 方法名 ( 参数列表 ){}
示例
public class SaleThreadTest {public static void main ( String [] args ) {SaleTask task = new SaleTask (); // 一个成员Thread t1 = new Thread ( task , " 窗口 1" ); // 共用同一个成员Thread t2 = new Thread ( task , " 窗口 2" ); // 共用同一个成员Thread t3 = new Thread ( task , " 窗口 3" ); // 共用同一个成员t1 . start ();t2 . start ();t3 . start ();}static class SaleTask implements Runnable {private int totalTickets = 10 ; // 售卖 10 张火车票//synchronized作用在成员方法上,因此synchronized 与成员有关private synchronized void saleTicket (){if ( totalTickets > 0 ){String name = Thread . currentThread (). getName ();System . out . println ( name + " 售卖火车票: " + totalTickets );totalTickets -- ;}}@Overridepublic void run () {while ( true ){saleTicket ();if ( totalTickets == 0 ) break ;try {Thread . sleep ( 100L );} catch ( InterruptedException e ) {e . printStackTrace ();}}}}}
同步代码块语法
synchronized ( 对象 ){}
示例
public class SaleThreadTest {public static void main ( String [] args ) {SaleTask task = new SaleTask (); // 一个成员Thread t1 = new Thread ( task , " 窗口 1" ); // 共用同一个成员Thread t2 = new Thread ( task , " 窗口 2" ); // 共用同一个成员Thread t3 = new Thread ( task , " 窗口 3" ); // 共用同一个成员t1 . start ();t2 . start ();t3 . start ();}static class SaleTask implements Runnable {private int totalTickets = 10 ; // 售卖 10 张火车票private Object o = new Object ();//synchronized作用在成员方法上,因此synchronized 与成员有关// private synchronized void saleTicket(){// if(totalTickets > 0){// String name = Thread.currentThread().getName();// System.out.println(name + "售卖火车票:" + totalTickets);// totalTickets --;// }// }@Overridepublic void run () {while ( true ){// saleTicket();synchronized ( o ){if ( totalTickets > 0 ){String name = Thread . currentThread (). getName ();System . out . println ( name + " 售卖火车票: " +totalTickets );totalTickets -- ;}}if ( totalTickets == 0 ) break ;try {Thread . sleep ( 100L );} catch ( InterruptedException e ) {e . printStackTrace ();}}}}}
synchronized锁实现原理
Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.同步是围绕称为内部锁或监视器锁的内部实体构建的。 (API 规范通常将此实体简称为 “ 监视器 ” 。)内在锁在同步的两个方面都起作用:强制对对象状态的独占访问并建立对可见性至关重要的事前关联。Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.每个对象都有一个与之关联的固有锁。按照约定,需要对对象的字段进行独占且一致的访问的线程必须在访问对象之前先获取对象的内在锁,然后在完成对它们的使用后释放该内在锁。据说线程在获取锁和释放锁之间拥有内部锁。只要一个线程拥有一个内在锁,其他任何线程都无法获得相同的锁。另一个线程在尝试获取锁时将阻塞。When a thread releases an intrinsic lock, a happens-before relationship is established between that action and any subsequent acquisition of the same lock.当线程释放内在锁时,该动作与任何随后的相同锁获取之间将建立事前发生的关系。When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception.当线程调用同步方法时,它会自动获取该方法对象的内在锁,并在方法返回时释放该内锁。 即使返回是由未捕获的异常引起的,也会发生锁定释放。
5. 线程同步-Lock
Synchronized code relies on a simple kind of reentrant lock. This kind of lock is easy to use, but has many limitations.同步代码依赖于一种简单的可重入锁。这种锁易于使用,但有很多限制。Lock objects work very much like the implicit locks used by synchronized code. As with implicit locks, only one thread can own a Lock object at a time.锁对象的工作方式非常类似于同步代码所使用的隐式锁。与隐式锁一样,一次只能有一个线程拥有一个Lock对象。The biggest advantage of Lock objects over implicit locks is their ability to back out of an attempt to acquire a lock. The tryLock method backs out if the lock is not available immediately or before a timeout expires (if specified). The lockInterruptibly method backs out if another thread sends an interrupt before the lock is acquired.与隐式锁相比,Lock 对象的最大优点是它们能够回避获取锁的企图。如果该锁不能立即或在超时到期之前不可用,则tryLock 方法将撤消(如果指定)。如果另一个线程在获取锁之前发送了中断,则lockInterruptibly方法将退出。
示例
import java . util . concurrent . locks . Lock ;import java . util . concurrent . locks . ReentrantLock ;public class LockDemo {public static void main ( String [] args ) {SaleTask task = new SaleTask (); // 一个成员Thread t1 = new Thread ( task , " 窗口 1" ); // 共用同一个成员Thread t2 = new Thread ( task , " 窗口 2" ); // 共用同一个成员Thread t3 = new Thread ( task , " 窗口 3" ); // 共用同一个成员t1 . start ();t2 . start ();t3 . start ();}static class SaleTask implements Runnable {private int totalTickets = 10 ; // 售卖 10 张火车票private Lock lock = new ReentrantLock (); // 创建一个可重入锁@Overridepublic void run () {while ( true ){//尝试获得锁if ( lock . tryLock ()){try {if ( totalTickets > 0 ){String name = Thread . currentThread (). getName ();System . out . println ( name + " 售卖火车票: " + totalTickets );totalTickets -- ;}} finally {lock . unlock (); // 解锁}}if ( totalTickets == 0 ) break ;try {Thread . sleep ( 100L );} catch ( InterruptedException e ) {e . printStackTrace ();}}}}}
6. 线程通信
Object类中的通信方法
public final native void notify (); // 唤醒一个在监视器上等待的线程public final native void notifyAll (); // 唤醒所有在监视器上等待的线程public final void wait () throws InterruptedException ; // 等待public final native void wait ( long timeout ) throws InterruptedException ; // 计时等待public final void wait ( long timeout , int nanos ) throwsInterruptedException ; // 计时等待
案例
小明每次没有生活费了就给他的爸爸打电话,他的爸爸知道了后就去银行存钱,钱存好了之后就通知小明去取。
分析
- a. 存钱和取钱都有一个共用的账户
- b. 存钱后需要通知取钱,然后等待下一次存钱
- c.取钱后需要通知存钱,然后等待下一次取钱
代码实现
package com . wq . thread . interact ;public class Account {private String name ;private double balance ;private boolean hasMoney = false ; // 存钱标志public Account ( String name ) {this . name = name ;}public synchronized void store ( double money ){if ( hasMoney ){ // 已经存钱了System . out . println ( name + " 的老爸等待通知存钱 " );try {wait ();} catch ( InterruptedException e ) {e . printStackTrace ();}} else {balance += money ;System . out . println ( name + " 的老爸存了 " + money + " 元钱 " );hasMoney = true ;notifyAll (); // 通知取钱}}public synchronized void draw ( double money ){if ( hasMoney ){ // 已经存钱了if ( balance < money ){ // 余额不足System . out . println ( name + " 向他老爸控诉没有钱了 " );hasMoney = false ;notify (); // 通知他老爸存钱} else {balance -= money ;System . out . println ( name + " 取了 " + money + " 元钱 " );}} else { // 没有存钱try {System . out . println ( name + " 等待他老爸存钱 " );wait (); // 等待存钱} catch ( InterruptedException e ) {e . printStackTrace ();}}}}package com . wq . thread . interact ;/*** 存钱任务*/public class StoreTask implements Runnable {private Account account ;private double money ;public StoreTask ( Account account , double money ) {this . account = account ;this . money = money ;}@Overridepublic void run () {while ( true ){account . store ( money );try {Thread . sleep ( 500 );} catch ( InterruptedException e ) {e . printStackTrace ();}}}}package com . wq . thread . interact ;/*** 取钱任务*/public class DrawTask implements Runnable {private Account account ;private double money ;public DrawTask ( Account account , double money ) {this . account = account ;this . money = money ;}@Overridepublic void run () {while ( true ){account . draw ( money );try {Thread . sleep ( 500 );} catch ( InterruptedException e ) {e . printStackTrace ();}}}}package com . wq . thread . interact ;public class AccountTest {public static void main ( String [] args ) {Account account = new Account ( " 小明 " );Thread t1 = new Thread ( new StoreTask ( account , 500 ));Thread t2 = new Thread ( new DrawTask ( account , 1000 ));t1 . start ();t2 . start ();}}
7. 线程状态
public enum State {/*** Thread state for a thread which has not yet started.*/NEW ,/*** Thread state for a runnable thread. A thread in the runnable* state is executing in the Java virtual machine but it may* be waiting for other resources from the operating system* such as processor.*/RUNNABLE ,/*** Thread state for a thread blocked waiting for a monitor lock.*/BLOCKED ,/*** Thread state for a waiting thread.*/WAITING ,/*** Thread state for a waiting thread with a specified waiting time.*/TIMED_WAITING ,/*** Thread state for a terminated thread.* The thread has completed execution.*/TERMINATED ;}