1.synchronized同步代码块
synchronized(obj){
.....
//同步代码块的代码
}
直接对obj对象同步监听,任何线程在修改指定的资源之前,首先对该资源加锁,在加锁期间其他线程无法修改该资源。
2.synchronized同步方法
1)类里的对象可以被多线程安全访问
public synchronized void draw(double drawAmount){ if (this.balance >= drawAmount) { System.out.println(Thread.currentThread().getName() + "取钱成功!吐出现金:" + drawAmount); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } this.balance = this.balance - drawAmount; System.out.println("\t余额为:" + balance); } else { System.out.println(Thread.currentThread().getName() + "取钱失败,余额不足!"); } }
总结:
1)synchronized可修饰方法,可修饰代码块,但不能修饰构造器,属性。
2)不要对线程安全的所有方法都进行同步。
3.同步锁(Lock)
显式加锁,显式解锁
ReentrantLock(可重入锁):一个线程可以对已被加锁的ReentrantLock锁再次加锁,ReentrantLock对象会维持一个计数器来追踪lock()方法的嵌套调用。
public class Account { private final ReentrantLock lock = new ReentrantLock(); public void draw(double drawAmount) { //上锁 lock.lock(); try { ......//操作代码 } finally { //解锁 lock.unlock(); } } }
4.死锁问题
当两个线程互相等待对方释放同步监视器时就会发生死锁,当陷入死锁,所有线程处于阻塞状态,无法继续。
四个必要条件:
3)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
4)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
传统的线程通信:
wait():导致当前线程等待
notify():唤醒等待线程中的单个线程
notifyAll():唤醒等待线程中的所有线程
public class Account { private String accountNo; private double balance; private boolean flag = false; public Account(String accountNo, double balance) { this.accountNo = accountNo; this.balance = balance; } public int hashCode() { return accountNo.hashCode(); } public boolean equals(Object object) { if (this == object) { return true; } if (object != null && object.getClass() == this.getClass()) { Account account = (Account) object; return account.getAccountNo().equals(account); } return false; } public String getAccountNo() { return accountNo; } public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public double getBalance() { return balance; } public synchronized void draw(double drawAmount) { try { if (!flag) { wait(); } else { if (this.balance >= drawAmount) { System.out.println(Thread.currentThread().getName() + "取钱成功!吐出现金:" + drawAmount); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } this.balance = this.balance - drawAmount; System.out.println("\t余额为:" + balance); flag = false; notifyAll(); } else { System.out.println(Thread.currentThread().getName() + "取钱失败,余额不足!"); } } } catch (InterruptedException e) { e.printStackTrace(); } } public synchronized void deposit(double depositAmount) { try { if (flag) { wait(); } else { System.out.println(Thread.currentThread().getName() + "存款:" + depositAmount); balance += depositAmount; System.out.println("\t余额为:" + balance); flag = true; notifyAll(); } } catch (InterruptedException e) { e.printStackTrace(); } } }
使用Condition类控制线程通信
Condition实例的方法:
await():类似于隐式同步监视器上的wait()方法
signal():类似于notify()方法
signalAll():类似于notifyAll()方法
public class Account { private String accountNo; private double balance; private boolean flag = false; private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); public Account(String accountNo, double balance) { this.accountNo = accountNo; this.balance = balance; } public int hashCode() { return accountNo.hashCode(); } public boolean equals(Object object) { if (this == object) { return true; } if (object != null && object.getClass() == this.getClass()) { Account account = (Account) object; return account.getAccountNo().equals(account); } return false; } public String getAccountNo() { return accountNo; } public void setAccountNo(String accountNo) { this.accountNo = accountNo; } public double getBalance() { return balance; } public void draw(double drawAmount) { lock.lock(); try { if (!flag) { condition.await(); } else { if (this.balance >= drawAmount) { System.out.println(Thread.currentThread().getName() + "取钱成功!吐出现金:" + drawAmount); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } this.balance = this.balance - drawAmount; System.out.println("\t余额为:" + balance); flag = false; condition.signalAll(); } else { System.out.println(Thread.currentThread().getName() + "取钱失败,余额不足!"); } } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public synchronized void deposit(double depositAmount) { lock.lock(); try { if (flag) { condition.await(); } else { System.out.println(Thread.currentThread().getName() + "存款:" + depositAmount); balance += depositAmount; System.out.println("\t余额为:" + balance); flag = true; condition.signalAll(); } } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } }显式和隐式线程通信
相关推荐
Win32 多线程的性能(1)... 1 <br/>Win32 多线程的性能(2)... 10 <br/>关于多线程的一些细节... 23 <br/>用VC++5.0 实 现 多 线 程 的 调 度 和 处 理... 25 <br/>一 多 任 务, 多 进 程 和 多 ...
目录: ...多线程编程初探 3.1 线程的基本概念 3.2 创建与同步线程 网络编程基础 4.1 套接字的概念与创建 4.2 服务器与客户端通信 高级文件操作 5.1 顺序文件与随机文件 5.2 文件的读写位置与偏移
目录: 函数指针与回调函数 1.1 函数指针的定义与使用 1.2 回调函数的概念 枚举与位操作 2.1 枚举类型的定义与应用 2.2 位操作与位运算 ...多线程编程初探 6.1 线程的基本概念 6.2 创建与同步线程
第9章 多线程编程 9.1 Linux线程概述 9.1.1 线程概述 9.1.2 线程机制的分类和特性 9.2 Linux线程编程 9.2.1 线程基本编程 9.2.2 线程之间的同步与互斥 9.2.3 线程属性 9.3 实验内容——“生产者消费者”实验 9.4 本...
对Java语言的每个语法都提供了一个或多个例程讲解 大量使用流程图表示程序的执行过程,使用结构图表示程序的内部状态 每章最后都给出了典型的练习题,让读者及时练习,巩固提高,并提供了参考答案 目录 第1篇 ...
对Java语言的每个语法都提供了一个或多个例程讲解 大量使用流程图表示程序的执行过程,使用结构图表示程序的内部状态 每章最后都给出了典型的练习题,让读者及时练习,巩固提高,并提供了参考答案 目录 第1篇 ...
通过作业,定时同步两个数据库 SQLSERVER高级注入技巧 利用反射实现ASP.NET控件和数据实体之间的双向绑定,并且在客户端自动验证输入的内容是否合法 asp.net报表解决方法 SQLDMO类的使用 SQL过程自动C#封装,支持从表到...
4.10 进程与多线程的区别 190 4.11 创建多线程应用程序 191 4.12 WinForm开发常见问题 194 4.12.1 如何设置运行时窗体的起始位置 194 4.12.2 如何使一个窗体在屏幕的最顶端 194 4.12.3 实现窗体渐显效果 194 4.12.4 ...
4.10 进程与多线程的区别 190 4.11 创建多线程应用程序 191 4.12 WinForm开发常见问题 194 4.12.1 如何设置运行时窗体的起始位置 194 4.12.2 如何使一个窗体在屏幕的最顶端 194 4.12.3 实现窗体渐显效果 194 4.12.4 ...
13_干活要知道在什么框架之下干活 14_结构体类型和变量定义及基本操作 15_结构体元素做函数参数pk结构指针做函数参数 16_结构体做函数基本操作 17_结构体做函数内存分配指针 18_结构中套一级指针 19_结构体中套二级...