Java复习-并发编程之synchronized
来源:互联网 发布:mplayerx mac dmg 编辑:程序博客网 时间:2024/05/20 11:34
在Java中,每一个对象都拥有一个锁标记(monitor),也称为监视器,多线程同时访问某个对象时,线程只有获取了该对象的锁才能访问。在Java中,可以使用synchronized关键字来标记一个方法或者代码块,当某个线程调用该对象的synchronized方法或者访问synchronized代码块时,这个线程便获得了该对象的锁,其他线程暂时无法访问这个方法,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁,其他线程才能执行这个方法或者代码块。
1、先看一个简单的例子:
package BasicConcept;import java.util.ArrayList;public class SynchrnoizedTest {public static void main(String[] args) {// TODO Auto-generated method stubInsertData insertData = new InsertData() ;Thread t1 = new Thread(insertData);Thread t2 = new Thread(insertData);t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}class InsertData implements Runnable{public ArrayList<Integer> arrayList = new ArrayList<Integer>();public void insert() {// TODO Auto-generated method stubfor (int i = 0; i < 500; i++) {if(!arrayList.contains(new Integer(i)) ) {System.out.println(Thread.currentThread().getName()+"在插入数据"+i);arrayList.add(i);}}}@Overridepublic void run() {// TODO Auto-generated method stubinsert();}}
我们可以看看运行结果:
我们明明希望得到的是新建两个线程往一个arrayList里装0-499个不同的数字,但是新建线程调用方法后发现,数字存入的很明显有重复的数字。为什么呢?正式因为线程安全问题,可能线程0执行到
if(!arrayList.contains(new Integer(i)) ) {System.out.println(Thread.currentThread().getName()+"在插入数据"+i);
的时候,发生了阻塞,这时候进入了线程1,此时i数据并未写入到arrayList中去,所以线程1依然可以通过if语句,想里插入i,进而导致重复。而在insert函数前加入synchronized关键字之后:
public synchronized void insert() {// TODO Auto-generated method stubfor (int i = 0; i < 500; i++) {if(!arrayList.contains(new Integer(i)) ) {System.out.println(Thread.currentThread().getName()+"在插入数据"+i);arrayList.add(i);}}}
我们看到结果是:
一直在执行线程0而并未进入线程1,且arryList最后存入的数据就为0-499;我们可以发现
synchronized关键字相当于对方法进行上锁了,只要在执行了insert方法后,别的线程只有在不再用insert
方法后才可能调用此方法。
而在insert函数里加入synchronized代码块之后:
public void insert() {// TODO Auto-generated method stubfor (int i = 0; i < 500; i++) {synchronized(arrayList) {if(!arrayList.contains(new Integer(i)) ) {System.out.println(Thread.currentThread().getName()+"在插入数据"+i);arrayList.add(i);}}}}
我们得到的结果是:
通过synchronized代码块对arraylist对象进行了上锁,只要此对象被使用,则知道完成插入一直都是使用当前线程才能使用这个arrayList对象!
总结下,关于一个对象的synchronized方法:
1)当一个线程正在访问一个对象的synchronized方法,那么其他线程不能访问该对象的其他synchronized方法。这个原因很简单,因为一个对象只有一把锁,当一个线程获取了该对象的锁之后,其他线程无法获取该对象的锁,所以无法访问该对象的其他synchronized方法。
2)当一个线程正在访问一个对象的synchronized方法,那么其他线程能访问该对象的非synchronized方法。这个原因很简单,访问非synchronized方法不需要获得该对象的锁,假如一个方法没用synchronized关键字修饰,说明它不会使用到临界资源,那么其他线程是可以访问这个方法的
3)如果一个线程A需要访问对象object1的synchronized方法fun1,另外一个线程B需要访问对象object2的synchronized方法fun1,即使object1和object2是同一类型),也不会产生线程安全问题,因为他们访问的是不同的对象,所以不存在互斥问题。
关于synchronized代码块:
此外,例子代码中为
synchronized(arrayList) {还可以为:
synchronized(this) {甚至还可以在类中new一个额外对象来上锁实现 synchronized代码块。
synchronized代码块使用起来比synchronized方法要灵活得多。因为也许一个方法中只有一部分代码只需要同步,如果此时对整个方法用synchronized进行同步,会影响程序执行效率。而使用synchronized代码块就可以避免这个问题,synchronized代码块可以实现只对需要同步的地方进行同步。
同时有一点要注意:对于synchronized方法或者synchronized代码块,当出现异常时,JVM会自动释放当前线程占用的锁,因此不会由于异常导致出现死锁现象。
如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:
1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;
2)线程执行发生异常,此时JVM会让线程自动释放锁。
- Java复习-并发编程之synchronized
- java并发编程之synchronized
- java并发编程之synchronized
- java 并发编程之synchronized。
- Java并发编程之synchronized
- Java并发编程之synchronized
- Java并发编程之synchronized
- JAVA并发编程学习笔记之synchronized
- JAVA并发编程学习笔记之synchronized
- JAVA并发编程学习笔记之synchronized
- JAVA并发编程学习笔记之synchronized
- JAVA并发编程学习笔记之synchronized
- java 并发编程(一)之synchronized
- java 并发编程(二)之synchronized实例
- java 并发编程(三)之synchronized
- Java 进阶 之 并发编程 Synchronized
- 【Java并发编程】之synchronized和Lock
- Java 多线程并发编程之 Synchronized 关键字
- ffmpeg入门系列教程(新API)示例 02
- 基于神经网络语言模型的中文新闻文本聚类算法
- 蓝桥杯—next_permutation()全排列函数
- Linux 限制SFTP用户只能访问某个目录
- Tensorflow实例-CNN处理句子相似度(下)
- Java复习-并发编程之synchronized
- 51nod 1019逆序数
- swwd
- 二叉树的最大深度
- BaseAdapter简单封装
- View工作原理(一)事件传递原理详解
- 2016蓝桥杯省赛 快速排序
- 冒泡排序算法
- 算法导论 练习题 6.5-8