java并发之线程同步(synchronized和锁机制)
正文
多个执行线程共享一个资源的情景,是并发编程中最常见的情景之一。多个线程读或者写相同的数据等情况时可能会导致数据不一致。为了解决这些问题,引入了临界区概念。临界区是一个用以访问共享资源的代码块,这个代码块在同一时间内只允许一个线程执行。
使用synchronized实现同步方法
- 在方法声明中加入synchronized关键字
1 public synchronized void addAmount(double amount) {
2 }
- 在代码块中使用synchronized关键字,obj一般可以使用this关键字表示本类对象
1 synchronized(obj){
2 }

1 public class Account {
2 private double balance;
3 public double getBalance() {
4 return balance;
5 }
6 public void setBalance(double balance) {
7 this.balance = balance;
8 }
9 public synchronized void addAmount(double amount) {
10 double tmp=balance;
11 try {
12 Thread.sleep(10);
13 } catch (InterruptedException e) {
14 e.printStackTrace();
15 }
16 tmp+=amount;
17 balance=tmp;
18 }
19 public synchronized void subtractAmount(double amount) {
20 double tmp=balance;
21 try {
22 Thread.sleep(10);
23 } catch (InterruptedException e) {
24 e.printStackTrace();
25 }
26 tmp-=amount;
27 balance=tmp;
28 }
29 }


1 public class Bank implements Runnable {
2 private Account account;
3 public Bank(Account account) {
4 this.account=account;
5 }
6 public void run() {
7 for (int i=0; i<100; i++){
8 account.subtractAmount(1000);
9 }
10 }
11 }


1 public class Company implements Runnable {
2 private Account account;
3 public Company(Account account) {
4 this.account=account;
5 }
6
7 public void run() {
8 for (int i=0; i<100; i++){
9 account.addAmount(1000);
10 }
11 }
12 }


1 public class Main {
2 public static void main(String[] args) {
3 Account account=new Account();
4 account.setBalance(1000);
5 Company company=new Company(account);
6 Thread companyThread=new Thread(company);
7 Bank bank=new Bank(account);
8 Thread bankThread=new Thread(bank);
9
10 companyThread.start();
11 bankThread.start();
12 try {
13 companyThread.join();
14 bankThread.join();
15 System.out.printf("Account : Final Balance: %f\n",account.getBalance());
16 } catch (InterruptedException e) {
17 e.printStackTrace();
18 }
19 }
20 }

使用非依赖属性实现同步

1 public class Cinema {
2 private long vacanciesCinema1;
3 private long vacanciesCinema2;
4
5 private final Object controlCinema1, controlCinema2;
6
7 public Cinema(){
8 controlCinema1=new Object();
9 controlCinema2=new Object();
10 vacanciesCinema1=20;
11 vacanciesCinema2=20;
12 }
13
14 public boolean sellTickets1 (int number) {
15 synchronized (controlCinema1) {
16 if (number<vacanciesCinema1) {
17 vacanciesCinema1-=number;
18 return true;
19 } else {
20 return false;
21 }
22 }
23 }
24
25 public boolean sellTickets2 (int number){
26 synchronized (controlCinema2) {
27 if (number<vacanciesCinema2) {
28 vacanciesCinema2-=number;
29 return true;
30 } else {
31 return false;
32 }
33 }
34 }
35
36 public boolean returnTickets1 (int number) {
37 synchronized (controlCinema1) {
38 vacanciesCinema1+=number;
39 return true;
40 }
41 }
42 public boolean returnTickets2 (int number) {
43 synchronized (controlCinema2) {
44 vacanciesCinema2+=number;
45 return true;
46 }
47 }
48 public long getVacanciesCinema1() {
49 return vacanciesCinema1;
50 }
51 public long getVacanciesCinema2() {
52 return vacanciesCinema2;
53 }
54 }

在同步块中使用条件(wait(),notify(),notifyAll())
- 上述三个方法都是Object 类的方法。
- 上述三个方法都必须在同步代码块中使用。
当一个线程调用wait()方法时,JVM将这个线程置入休眠,并且释放控制这个同步代码块的对象,同时允许其他线程执行这个对象控制的其他同步代码块。为了唤醒这个线程,必须在这个对象控制的某个同步代码块中调用notify()或者notifyAll()方法。

1 public synchronized void set(){
2 while (storage.size()==maxSize){
3 try {
4 wait();
5 } catch (InterruptedException e) {
6 e.printStackTrace();
7 }
8 }
9 storage.add(new Date());
10 System.out.printf("Set: %d\n", storage.size());
11 notify();
12 }
13 public synchronized void get(){
14 while (storage.size()==0){
15 try {
16 wait();
17 } catch (InterruptedException e) {
18 e.printStackTrace();
19 }
20 }
21 System.out.printf("Get: %d: %s\n",storage.size(),((LinkedList<?>)storage).poll());
22 notify();
23 }

使用锁实现同步

1 public class PrintQueue {
2 private final Lock queueLock=new ReentrantLock();
3
4 public void printJob(Object document){
5 queueLock.lock();
6
7 try {
8 Long duration=(long)(Math.random()*10000);
9 System.out.printf("%s: PrintQueue: Printing a Job during %d seconds\n",Thread.currentThread().getName(),(duration/1000));
10 Thread.sleep(duration);
11 } catch (InterruptedException e) {
12 e.printStackTrace();
13 } finally {
14 queueLock.unlock();
15 }
16 }
17 }

1 private final Lock queueLock=new ReentrantLock();
1 queueLock.lock();
1 queueLock.unlock();
使用读写锁实现同步数据访问

1 public void setPrices(double price1, double price2) {
2 lock.writeLock().lock();
3 this.price1=price1;
4 this.price2=price2;
5 lock.writeLock().unlock();
6 }


1 public double getPrice1() {
2 lock.readLock().lock();
3 double value=price1;
4 lock.readLock().unlock();
5 return value;
6 }
7 public double getPrice2() {
8 lock.readLock().lock();
9 double value=price2;
10 lock.readLock().unlock();
11 return value;
12 }

在锁中使用多条件(Multri Condition)

1 private Condition lines;
2 private Condition space;
3 */
4 public void insert(String line) {
5 lock.lock();
6 try {
7 while (buffer.size() == maxSize) {
8 space.await();
9 }
10 buffer.offer(line);
11 System.out.printf("%s: Inserted Line: %d\n", Thread.currentThread()
12 .getName(), buffer.size());
13 lines.signalAll();
14 } catch (InterruptedException e) {
15 e.printStackTrace();
16 } finally {
17 lock.unlock();
18 }
19 }
20 public String get() {
21 String line=null;
22 lock.lock();
23 try {
24 while ((buffer.size() == 0) &&(hasPendingLines())) {
25 lines.await();
26 }
27
28 if (hasPendingLines()) {
29 line = buffer.poll();
30 System.out.printf("%s: Line Readed: %d\n",Thread.currentThread().getName(),buffer.size());
31 space.signalAll();
32 }
33 } catch (InterruptedException e) {
34 e.printStackTrace();
35 } finally {
36 lock.unlock();
37 }
38 return line;
39 }
java并发之线程同步(synchronized和锁机制)的更多相关文章
- java多线程:线程同步synchronized(不同步的问题、队列与锁),死锁的产生和解决
0.不同步的问题 并发的线程不安全问题: 多个线程同时操作同一个对象,如果控制不好,就会产生问题,叫做线程不安全. 我们来看三个比较经典的案例来说明线程不安全的问题. 0.1 订票问题 例如前面说过的 ...
- Java多线程(五) —— 线程并发库之锁机制
参考文献: http://www.blogjava.net/xylz/archive/2010/07/08/325587.html 一.Lock与ReentrantLock 前面的章节主要谈谈原子操作 ...
- Java并发包——线程同步和锁
Java并发包——线程同步和锁 摘要:本文主要学习了Java并发包里有关线程同步的类和锁的一些相关概念. 部分内容来自以下博客: https://www.cnblogs.com/dolphin0520 ...
- java核心知识点学习----多线程并发之线程同步
1.什么是线程同步? 多线程编程是很有趣的事情,它很容易出现"错误情况",这种情况不是由编码造成的,它是由系统的线程调度造成的,当使用多个线程来访问同一个数据时,很容易出现&quo ...
- Java核心知识点 --- 线程中如何创建锁和使用锁 Lock , 设计一个缓存系统
理论知识很枯燥,但这些都是基本功,学完可能会忘,但等用的时候,会发觉之前的学习是非常有意义的,学习线程就是这样子的. 1.如何创建锁? Lock lock = new ReentrantLock(); ...
- 关于Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇高质量的博文)
Java多线程的线程同步和线程通信的一些小问题(顺便分享几篇质量高的博文) 前言:在学习多线程时,遇到了一些问题,这里我将这些问题都分享出来,同时也分享了几篇其他博客主的博客,并且将我个人的理解也分享 ...
- Java多线程02(线程安全、线程同步、等待唤醒机制)
Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...
- Java中的线程同步
Java 中的线程同步问题: 1. 线程同步: 对于访问同一份资源的多个线程之间, 来进行协调的这个东西. 2. 同步方法: 当某个对象调用了同步方法时, 该对象上的其它同步方法必须等待该同步方法执行 ...
- java并发包&线程池原理分析&锁的深度化
java并发包&线程池原理分析&锁的深度化 并发包 同步容器类 Vector与ArrayList区别 1.ArrayList是最常用的List实现类,内部是通过数组实现的, ...
随机推荐
- Vue中之nextTick函数源码分析
Vue中之nextTick函数源码分析 1. 什么是Vue.nextTick()?官方文档解释如下:在下次DOM更新循环结束之后执行的延迟回调.在修改数据之后立即使用这个方法,获取更新后的DOM. 2 ...
- Scrapy架构及其组件之间的交互
最近在学Python,同时也在学如何使用python抓取数据,于是就被我发现了这个非常受欢迎的Python抓取框架Scrapy,下面一起学习下Scrapy的架构,便于更好的使用这个工具. 一.概述 下 ...
- 如何使用 C# 爬虫获得专栏博客更新排行
昨天,梦姐问我们,她存在一个任务,找到 关注数排行100 和 浏览量排行100 的专栏博客,在2017年还有更新的专栏. 梦姐说他要出去一趟,M大神在吃饭,于是我估算时间,只有半个钟. 整理一下:半个 ...
- win10 uwp 从StorageFile获取文件大小
本文主要:获取文件大小 private async Task<ulong> FileSize(Windows.Storage.StorageFile file) { var size = ...
- Javascript常见浏览器兼容问题
常见浏览器原生javascript兼容性问题主要分为以下几类: 一.Dom 1.获取HTML元素,兼容所有浏览器方法:document.getElementById("id")以I ...
- CURL常用命令记录--用于简单测试接口
curl命令是一个利用URL规则在命令行下工作的文件传输工具.它支持文件的上传和下载,所以是综合传输工具,但按传统,习惯称curl为下载工具.作为一款强力工具,curl支持包括HTTP.HTTPS.f ...
- vue.js快速搭建图书管理平台
前 言 上一期简单讲解了vue的基本语法,这一次我们做一个小项目,搭建一个简单的图书管理平台,能够让我们更深刻的理解这门语言的妙用. 1.DEMO样式 首先我们需要搭建一个简单的demo样式 ...
- Ubuntu on win10
大家看到这个题目应该都知道这个东西吧,或许也都知道咋安装啥的,我只是想分享一下自己安装它的过程同时可以对那些有需要的人给予帮助!!! 1. 打开开发者模式(如下图) 像上面这样打开开发人员模式,过程会 ...
- java调用oracle数据库发布WebService
package com.hyan.service; import java.io.FileInputStream;import java.sql.Connection;import java.sql. ...
- Windows下mysql5.5主从同步
前置条件: A主机(作为主服务器) 环境:Win7,mysql5.5 IP:172.17.42.82 B主机(作为从服务器) 环境:Win7,mysql5.5 IP:172.17.42.156 主服务 ...