第二章 Basic Thread Synchronization (基础线程同步) 【上】
2017-08-12 15:50
597 查看
涉及的内容
同步一个方法
同步类中分配一个独立属性
在同步代码中使用条件
使用Lock锁定代码块
同步数据的读写锁
修改Lock公平模式
在Lock中使用多条件
对于同步的代码块称为critical section (临界断面)
为了实现这个同步将会介绍两种同步方法:
关键字:synchronized
Lock的接口和它的实现类
例子:模拟取存款过程
public class Account {
private double balance;
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public synchronized void addAmount(double amount){
System.out.printf("增加了金额++++++:%f\n", amount);
double tmp = balance;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
tmp += amount;
balance=tmp;
}
public synchronized void substractAmount(double amount){
System.out.printf("减少了金额------:%f\n", amount);
double tmp = balance;
try {
Thread.sleep(10);
} catch (InterruptedException e){
e.printStackTrace();
}
tmp -= amount;
balance = tmp;
}
}
总结:
1、synchronized进行同步操作保证最后的结果是准确的。
2、你可以删除synchronized测试结果。
public class Cinema {
private long vacanciesCinema1;
private long vacanciesCinema2;
private final Object controlCinema1, controlCinema2;
/**
* 初始20张票
*/
public Cinema(){
controlCinema1 = new Object();
controlCinema2 = new Object();
vacanciesCinema1 = 20;
vacanciesCinema2 = 20;
}
/**
* 售票
* @param number
* @return
*/
public boolean sellTickets1(int number){
synchronized (controlCinema1){
if(number < vacanciesCinema1){
vacanciesCinema1 -= number;
return true;
} else {
return false;
}
}
}
/**售票
* @param number
* @return
*/
public boolean sellTickets2 (int number){
synchronized (controlCinema2){
if(number < vacanciesCinema2){
vacanciesCinema2 -= number;
return true;
} else {
return false;
}
}
}
/**
* 退票
* @param number
* @return
*/
public boolean returnTicket1 (int number){
synchronized (controlCinema1){
vacanciesCinema1 += number;
return true;
}
}
/**
* 退票
* @param number
* @return
*/
public boolean returnTicket2 (int number){
synchronized (controlCinema2){
vacanciesCinema2 += number;
return true;
}
}
/**
* 返回余票
* @return
*/
public long getVacanciesCinema1(){
return vacanciesCinema1;
}
/**
* 返回余票
* @return
*/
public long getVacanciesCinema2(){
return vacanciesCinema2;
}
}
总结:
1、创建的controlCinema1和controlCinema2并没有实际的作用,它只是作为关联锁定花括号的代码,
(说白了就是如果锁定controlCinema2代码中所有对象,每次只一个线程访问这些对象)。
package com.jack;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
public class EventStorage {
private int maxSize;
private List<Date> storage;
public EventStorage(){
maxSize=10;
storage=new LinkedList<>();
}
public synchronized void set(){
while (storage.size()==maxSize){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storage.add(new Date());
System.out.printf("++当然前仓库: %d\n",storage.size());
notifyAll();
}
public synchronized void get(){
while (storage.size()==0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.printf("--当然前仓库: %d: %s\n",storage.
size(),((LinkedList<?>)storage).poll());
notifyAll();
}
}
总结:
1、创建一个仓库类,有添加和删除,创建生产线程和消费线程。当等于10时候等待,唤醒对方。
2、wait等待,notifyAll()唤醒所有线程
1、允许同步块更加灵活。
2、Lock接口比synchronized提供额外的功能,增加tryLock()返回同步块的状态
3、Lock允许读写分离
4、Lock性能比synchronized关键字更优。
例子:使用Lock同步代码块模拟打印队列
package com.jack;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class PrintQueue {
private final Lock queueLock = new ReentrantLock();
public void printJob(Object document){
queueLock.lock();
try {
Long duration = (long) (Math.random()*10000);
System.out.printf(Thread.currentThread().getName()
+ ":打印队列:打印一个工作持续时间 %s ",(duration/1000)
+ " seconds");
Thread.sleep(duration);
} catch (InterruptedException e){
e.printStackTrace();
}finally{
queueLock.unlock();
}
}
}
总结:
1、private final Lock queueLock = new ReentrantLock(); 是关键。首先为该类配一个锁
2、lock()方法锁定的意思,第一个进来之后锁住,直到执行完,(类似卵子受精就是这个例子)
3、ReentrantLock允许递归调用
4、注意避免死锁
同步一个方法
同步类中分配一个独立属性
在同步代码中使用条件
使用Lock锁定代码块
同步数据的读写锁
修改Lock公平模式
在Lock中使用多条件
简介
同步类似就是车过收费站,一杆一车,排队出收费站,不许并行。对于同步的代码块称为critical section (临界断面)
为了实现这个同步将会介绍两种同步方法:
关键字:synchronized
Lock的接口和它的实现类
1、同步方法(synchronized)
注意:对于一个类有个static的同步方法和非static方法,两个线程可以同时进入同一对象不同方法,如果同时修改同一个数据,将会产生数据不一致。例子:模拟取存款过程
public class Account {
private double balance;
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public synchronized void addAmount(double amount){
System.out.printf("增加了金额++++++:%f\n", amount);
double tmp = balance;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
tmp += amount;
balance=tmp;
}
public synchronized void substractAmount(double amount){
System.out.printf("减少了金额------:%f\n", amount);
double tmp = balance;
try {
Thread.sleep(10);
} catch (InterruptedException e){
e.printStackTrace();
}
tmp -= amount;
balance = tmp;
}
}
public class Bank implements Runnable{ private Account account; public Bank(Account account) { super(); this.account = account; } @Override public void run() { for (int i=0; i< 10; i++){ account.substractAmount(1000); } } }
public class Company implements Runnable{ private Account account; public Company(Account account) { super(); this.account = account; } @Override public void run() { for(int i=0; i<10; i++){ account.addAmount(1000); } } }
public class Main { public static void main(String[] args){ Account account = new Account(); account.setBalance(1000); Company company = new Company(account); Thread companyThread = new Thread(company); Bank bank = new Bank(account); Thread bankThread = new Thread(bank); System.out.printf("账户:初始化金额: %f\n", account.getBalance()); companyThread.start(); bankThread.start(); try{ companyThread.join(); bankThread.join(); System.out.printf("账户:最终金额:%f\n", account.getBalance()); } catch (InterruptedException e){ e.printStackTrace(); } } }日志:
总结:
1、synchronized进行同步操作保证最后的结果是准确的。
2、你可以删除synchronized测试结果。
2、在同步类分配独立属性
模拟电影院两个放映室和两个购票处public class Cinema {
private long vacanciesCinema1;
private long vacanciesCinema2;
private final Object controlCinema1, controlCinema2;
/**
* 初始20张票
*/
public Cinema(){
controlCinema1 = new Object();
controlCinema2 = new Object();
vacanciesCinema1 = 20;
vacanciesCinema2 = 20;
}
/**
* 售票
* @param number
* @return
*/
public boolean sellTickets1(int number){
synchronized (controlCinema1){
if(number < vacanciesCinema1){
vacanciesCinema1 -= number;
return true;
} else {
return false;
}
}
}
/**售票
* @param number
* @return
*/
public boolean sellTickets2 (int number){
synchronized (controlCinema2){
if(number < vacanciesCinema2){
vacanciesCinema2 -= number;
return true;
} else {
return false;
}
}
}
/**
* 退票
* @param number
* @return
*/
public boolean returnTicket1 (int number){
synchronized (controlCinema1){
vacanciesCinema1 += number;
return true;
}
}
/**
* 退票
* @param number
* @return
*/
public boolean returnTicket2 (int number){
synchronized (controlCinema2){
vacanciesCinema2 += number;
return true;
}
}
/**
* 返回余票
* @return
*/
public long getVacanciesCinema1(){
return vacanciesCinema1;
}
/**
* 返回余票
* @return
*/
public long getVacanciesCinema2(){
return vacanciesCinema2;
}
}
public class TicketOffice1 implements Runnable{ private Cinema cinema; public TicketOffice1(Cinema cinema) { super(); this.cinema = cinema; } @Override public void run() { cinema.sellTickets1(3); cinema.sellTickets1(2); cinema.sellTickets2(2); cinema.returnTicket1(3); /*cinema.sellTickets1(5); cinema.sellTickets2(2); cinema.sellTickets2(2); cinema.sellTickets2(2);*/ } }
public class TicketOffice2 implements Runnable{ private Cinema cinema; public TicketOffice2(Cinema cinema) { super(); this.cinema = cinema; } @Override public void run() { cinema.sellTickets2(3); cinema.sellTickets2(4); /*cinema.sellTickets1(2); cinema.sellTickets1(1); cinema.returnTicket2(2); cinema.sellTickets1(3); cinema.sellTickets2(2); cinema.sellTickets1(2);*/ } }
public class Main { public static void main(String[] args){ Cinema cinema = new Cinema(); TicketOffice1 ticketOffice1 = new TicketOffice1(cinema); Thread thread1 = new Thread(ticketOffice1, "TicketOffice1"); TicketOffice2 ticketOffice2 = new TicketOffice2(cinema); Thread thread2 = new Thread(ticketOffice2, "TicketOffice2"); thread1.start(); thread2.start(); try{ thread1.join(); thread2.join(); }catch (InterruptedException e){ e.printStackTrace(); } System.out.printf("放映室1空闲的数量:%d\n", cinema.getVacanciesCinema1()); System.out.printf("放映室2空闲的数量:%d\n", cinema.getVacanciesCinema2()); } }
总结:
1、创建的controlCinema1和controlCinema2并没有实际的作用,它只是作为关联锁定花括号的代码,
(说白了就是如果锁定controlCinema2代码中所有对象,每次只一个线程访问这些对象)。
3、在同步代码中使用条件
生产者-消费者模型(wait() notify() notifyAll())package com.jack;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
public class EventStorage {
private int maxSize;
private List<Date> storage;
public EventStorage(){
maxSize=10;
storage=new LinkedList<>();
}
public synchronized void set(){
while (storage.size()==maxSize){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
storage.add(new Date());
System.out.printf("++当然前仓库: %d\n",storage.size());
notifyAll();
}
public synchronized void get(){
while (storage.size()==0){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.printf("--当然前仓库: %d: %s\n",storage.
size(),((LinkedList<?>)storage).poll());
notifyAll();
}
}
package com.jack; public class Producer implements Runnable{ private EventStorage storage; public Producer(EventStorage storage) { super(); this.storage = storage; } @Override public void run() { for (int i=0; i <100; i++){ storage.set(); } } }
package com.jack; public class Consumer implements Runnable{ private EventStorage storage; public Consumer(EventStorage storage) { super(); this.storage = storage; } @Override public void run() { for (int i=0; i<100; i++){ storage.get(); } } }
package com.jack; public class Main { public static void main(String[] args){ EventStorage storage = new EventStorage(); Producer producer = new Producer(storage); Thread thread1 = new Thread(producer); Consumer consumer = new Consumer(storage); Thread thread2 = new Thread(consumer); thread2.start(); thread1.start(); } }
总结:
1、创建一个仓库类,有添加和删除,创建生产线程和消费线程。当等于10时候等待,唤醒对方。
2、wait等待,notifyAll()唤醒所有线程
4、采用Lock锁定同步块
Lock优点(ReentrantLock)1、允许同步块更加灵活。
2、Lock接口比synchronized提供额外的功能,增加tryLock()返回同步块的状态
3、Lock允许读写分离
4、Lock性能比synchronized关键字更优。
例子:使用Lock同步代码块模拟打印队列
package com.jack;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class PrintQueue {
private final Lock queueLock = new ReentrantLock();
public void printJob(Object document){
queueLock.lock();
try {
Long duration = (long) (Math.random()*10000);
System.out.printf(Thread.currentThread().getName()
+ ":打印队列:打印一个工作持续时间 %s ",(duration/1000)
+ " seconds");
Thread.sleep(duration);
} catch (InterruptedException e){
e.printStackTrace();
}finally{
queueLock.unlock();
}
}
}
package com.jack; public class Job implements Runnable{ private PrintQueue printQueue; public Job(PrintQueue printQueue) { super(); this.printQueue = printQueue; } @Override public void run() { System.out.printf("%s:去打印一个文档\n", Thread.currentThread().getName()); printQueue.printJob(new Object()); System.out.printf("%s: 这个文档已经打印了\n", Thread.currentThread().getName()); } }
package com.jack; public class Main { public static void main(String[] args){ PrintQueue printQueue = new PrintQueue(); Thread thread[] = new Thread[10]; for (int i=0; i<10; i++){ thread[i]= new Thread(new Job(printQueue), "线程 " + i); } for(int i=0; i<10; i++){ thread[i].start(); } } }
总结:
1、private final Lock queueLock = new ReentrantLock(); 是关键。首先为该类配一个锁
2、lock()方法锁定的意思,第一个进来之后锁住,直到执行完,(类似卵子受精就是这个例子)
3、ReentrantLock允许递归调用
4、注意避免死锁
相关文章推荐
- 第二章 Basic Thread Synchronization (基础线程同步) 【下】
- 第二章线程同步基础
- Java7并发编程指南——第二章:线程同步基础
- A Basic Example of Threads Synchronization in Python, python中的线程同步示例
- 第三章 Thread Synchronization Utilities(线程同步工具类)【下】
- 【JAVA】 基础练习 BASIC-12 十六进制转八进制
- What is the basic difference between NSTimer, NSTask, NSThread and NSRunloop?
- 蓝桥杯基础练习BASIC-6 杨辉三角形
- 蓝桥杯-基础练习-BASIC-6-杨辉三角形
- JAVA初窥:Thread线程基础
- 斯坦福大学自然语言处理第二课“文本处理基础(Basic Text Processing)”
- Java Concurrency in Practice :基础知识(线程同步)
- java基础知识之初识java之第二章
- [Java] Thread-05- 线程同步-生产者与消费者的经典问题
- 算法导论详解(1) 第二章算法基础+python实现
- 蓝桥杯 BASIC-3 基础练习 字母图形
- jquery基础教程 - 第二章 选择元素
- 基础练习 BASIC-2 01字串
- c++静态成员函数与线程同步(static member functions and thread-safety)
- Java线程编程中Thread类的基础学习教程