第二章 Basic Thread Synchronization (基础线程同步) 【上】
来源:互联网 发布:贵州大数据发展 编辑:程序博客网 时间:2024/05/22 04:36
涉及的内容
- 同步一个方法
- 同步类中分配一个独立属性
- 在同步代码中使用条件
- 使用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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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、注意避免死锁
阅读全文
0 0
- 第二章 Basic Thread Synchronization (基础线程同步) 【上】
- 第二章 Basic Thread Synchronization (基础线程同步) 【下】
- 第三章 Thread Synchronization Utilities(线程同步工具类)【上】
- 第三章 Thread Synchronization Utilities(线程同步工具类)【下】
- 第二章线程同步基础
- ACE线程安全与同步(Thread Safety and Synchronization)
- ACE线程安全与同步(Thread Safety and Synchronization)
- Java线程基础(二):Synchronization
- Java学习之线程同步(Synchronization)
- 第二部分:线程同步基础1
- 第二部分:线程同步基础2
- 第二部分:线程同步基础3
- Synchronization 同步
- Delphi Thread 线程同步
- Thread 线程同步
- iOS:多线程编程指南(三)--线程同步 Synchronization
- Java7并发编程指南——第二章:线程同步基础
- C#中的多线程 -第二部分:线程同步基础
- 弃。
- 5. Longest Palindromic Substring
- datatable指定页码分页
- KindEditor/API文档
- Unity不同脚本之间的执行顺序
- 第二章 Basic Thread Synchronization (基础线程同步) 【上】
- HDOJ1798 Doing Homework again(贪心)
- Java程序入门(三)
- 第一次恋爱就这么结束了,又一次成了单身狗
- [Leetcode] 350. Intersection of Two Arrays II 解题报告
- ssh免密码登录的坑
- KindEditor/常见问题
- 每日一点Js(五)
- SpringCloud(五):Ribbon了解