java线程(4)——线程同步的锁技术
同步
同步,字面来看,有点一起工作的意思。但在线程同步中,“同”意为协同、互相配合。
比如:
A、B两个线程,并不是说两个线程必须同时一起工作,而是说互相配合工作,在某个时间可能线程A要等线程B去工作,之后线程A才能继续工作。如果理解不了,可以参考java线程(2)——模拟生产者与消费者中的例子。
思考:
为什么会有线程同步?上面例子中线程A为什么要等B工作之后才能继续工作?
在生产者和消费者的例子中,作为消费者,如果生产者还没生产,他就没办法消费只能等着,否则就会出现问题。同样,生产者也不能无止尽的生产,毕竟篮子的容量是有限的。
如果这个例子看不出来问题的严重性,我们可以想想银行取钱的例子,出现问题这后果就相当严重了。所以,多线程如果使用不当,很容易出现线程不安全的问题。尤其涉及同步问题时,一定要小心使用。
实现方式
主要有两种:synchronized和lock,前者被称为内置锁,后者叫外置锁。
关于这两者的不同之处,介绍之后再比较。
1、 synchronized关键字
在消费者和生产者的例子中,我们使用到了synchronized关键字,将篮子的“取”和“放”都做了限制,来实现线程同步。
2、lock
先来看一下他的接口定义,也是在包java.util.concurrent下。
package java.util.concurrent.locks;
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
void unlock();
Condition newCondition();
}
在上篇博客中介绍了一个使用synchronized关键字实现打印当前时间的方法,我们这里来修改一下。
/**
* 获得当前时间
*/
public static void getTime() {
lock.lock();
try {
System.out.println("1、进入获取时间方法=====");
Date date = new Date();
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = format.format(date);
System.out.println("2、" + Thread.currentThread().getName() + ":"
+ time);
System.out.println("3、获取时间成功=====");
System.out.println();
} finally {
lock.unlock();
}
}
//调用
static Lock lock=null;
public static void main(String[] args) {
lock = new ReentrantLock();
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
@Override
public void run() {
getTime();
}
}).start();
}
}
结果同样满足条件:
读写锁
Lock中的另一个亮点就是对读写锁的支持。在读写锁中,把对共享资源的访问者划分为读者和写者,读者进行读访问,写者进行写操作。但是,一个读写锁同时能有一个或多个读者,但不能同时既有读者又有写者。
java中的类为ReadWriteLock,提供了读锁和写锁的方法,返回类型都是Lock
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
举个例子:
在例子中,data为所要读写的数据,提供了读和写的方法。
private Object data = null;// 共享数据
/**
* 读数据
*/
public void get() {
try {
//准备数据
System.out.println(Thread.currentThread().getName()
+ " be ready to read data!");
//sleep一段时间,主要为了更明显的体现出差别,无实际意义
Thread.sleep((long) (Math.random() * 1000));
//打印取出数据
System.out.println(Thread.currentThread().getName()
+ "have read data :" + data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 写数据
*
* @param data
*/
public void put(Object data) {
try {
System.out.println(Thread.currentThread().getName()
+ " be ready to write data!");
Thread.sleep((long) (Math.random() * 1000));
this.data = data; // 给data赋值
System.out.println(Thread.currentThread().getName()
+ " have write data: " + data);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
执行结果:
从结果上看,当程序刚启动时,多个读写线程同时触发,等待执行。无法实现“多读”,也影响了写的操作。
那么,现在来看下加上读写锁之后的效果。
ReadWriteLock rwl = new ReentrantReadWriteLock();
/**
* 读数据
*/
public void get(){
rwl.readLock().lock(); //读锁
try {
....略
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
rwl.readLock().unlock(); //释放读锁
}
}
与上面没有使用读写锁相比,最大的不同在于,他可以实现“多读”,并且“读”与“写”互斥。例如:Thread0,2,4进入之后,可以同时读数据。并没有多条写数据同时写。
点睛之笔
1)Lock与ReadWriteLock
以Lock第一个例子ReentrantLock来说,他实现了标准的互斥操作,有点“独占”的感觉。这种情况下,不允许多读,多写,读写等情况发生。
读写锁ReadWriteLock中,允许多个读线程同时访问一个资源,但不允许多个写线程同时访问。更符合实际操作和需要。
2)Lock与synchronized
synchronized比较武断,只能实现互斥,无法实现读写锁的允许多读操作。在并发量比较小的情况下,他是一个不错的选择。但并发量较大的话,他的性能下降很严重。
Lock锁技术除了第一点介绍的优点外,他还具有可重入性,即可以进行多次加锁,也更具公平性。不过为了避免死锁,需要在finally中释放锁。
java线程(4)——线程同步的锁技术的更多相关文章
- Java 虚拟机:互斥同步、锁优化及synchronized和volatile
互斥同步 互斥同步(Mutual Exclusion & Synchronization)是常见的一种并发正确性保证手段.同步是指子啊多个线程并发访问共享数据时,保证共享数据在同一时刻只能被一 ...
- Java多线程02(线程安全、线程同步、等待唤醒机制)
Java多线程2(线程安全.线程同步.等待唤醒机制.单例设计模式) 1.线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量 ...
- java 线程Thread 技术--线程状态与同步问题
线程技术第三篇: 线程的状态: 1. 创建状态: 当用new 操作符创建一个新的线程对象时,该线程就处于创建状态,系统不为它分配资源 2.可运行状态:当线程调用start 方法将为线程分配必须的系统资 ...
- Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)
多线程介绍 学习多线程之前,我们先要了解几个关于多线程有关的概念.进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线 ...
- JAVA语言规范-线程和锁章节之同步、等待和通知
JAVA语言规范:线程和锁 1 同步 java编程语言提供了线程间通信的多种机制.这些方法中最基本的是同步化,此方法是使用监视器实现的.JAVA中每个对象与一个监视器相关联,一个线程可以加锁和解锁监视 ...
- Java线程:线程的同步与锁
一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. public ...
- java线程(2)--同步和锁
参考转载:http://rainyear.iteye.com/blog/1734311 http://turandot.iteye.com/blog/1704027 http://www.cnblog ...
- Java多线程-线程的同步与锁
一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏.例如:两个线程ThreadA.ThreadB都操作同一个对象Foo对象,并修改Foo对象上的数据. package ...
- (转)Java线程:线程的同步与锁
Java线程:线程的同步与锁 一.同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏. 例如:两个线程ThreadA.ThreadB都操作同一个对象Fo ...
随机推荐
- qt项目:员工信息管理系统
开发一个员工信息管理系统 一.项目具体要求: 1.用qt开发界面,数据库用QSqlite 数据库文件名:demostudent.db 2.通过界面能够查看到数据库中员工信息表中内容,包括员工姓名.年龄 ...
- P1247 取火柴游戏
题目描述 输入k及k个整数n1,n2,-,nk,表示有k堆火柴棒,第i堆火柴棒的根数为ni:接着便是你和计算机取火柴棒的对弈游戏.取的规则如下:每次可以从一堆中取走若干根火柴,也可以一堆全部取走,但不 ...
- vector基础操作
//vector< T> vec; //构造一个名为vec的储存数据类型为T的动态数组.其中T为需要储存的数据类型 //初始时vec为空 //push_back 末尾添加一个元素 //po ...
- poj_3256_Cow Picnic
The cows are having a picnic! Each of Farmer John's K (1 ≤ K ≤ 100) cows is grazing in one of N (1 ≤ ...
- jquery 节点
$("ul li:eq(3)") // 元素的index位置工0开始计数,所以这里的3实际为第4个元素 $("ul").find("li" ...
- ERROR: bootstrap checks failed
错误描述:Linux默认配置的参数过小,需要自己设置 max file descriptors [4096] for elasticsearch process is too low, increas ...
- (译)JavaScript 中的正则表达式(RegEx)实操——快速掌握正则表达式,伴有随手可练的例子————(翻译未完待续)
(原文:https://blog.bitsrc.io/a-beginners-guide-to-regular-expressions-regex-in-javascript-9c58feb27eb4 ...
- CSS3新特性回顾
CSS3 介绍 开始实例 新特征简介 强大的CSS选择器 抛弃图片的视觉效果 盒模型变化(多列布局和弹性盒模型) 阴影效果 Web字体和web Font 图标 CSS33过渡与动画交互效果 媒体查询 ...
- CSS3实现3D球体旋转动画
html <div class="ball-box"> <div class="ball"> <div class="l ...
- 责任链模式的使用-Netty ChannelPipeline和Mina IoFilterChain分析
本文来自网易云社区 作者:乔安然 1. Chain of Responsiblity 定义: 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链 ...