一、共享资源竞争问题

在Java语言的并发编程中,由于我们不知道线程实际上在何时运行,所以在实际多线程编程中,如果两个线程访问相同的资源,那么由于线程运行的不确定性便会在这种多线程中产生访问错误。所以为了避免这一情况的发生,我们在编程的时候需要把并发执行的线程中用于访问这一共享资源的方法进行同步处理,以避免并发对于共享资源产生的影响。

并发模式在解决线程冲突的问题时,基本上都是采用序列化访问共享资源的方案。这在我的理解中,就是我们要控制同一时刻只能让一个线程对这一共享资源进行访问。

二、synchronized关键字的使用

1.synchronized对于类普通成员方法的修饰

Java语言中,每一个对象都含有单一的锁(监视器)。而synchronized的作用之一就是修饰使用了共享资源的成员方法,这样在线程通过对象调用该方法时,该对象都会被加锁。这时候如果需要调用该对象的另一个synchronized方法,则需要在第一个方法调用完毕后再进行,这就实现了最基本的同步。

例1:使用synchronized修饰方法和未修饰方法的区别

(1)使用synchronized修饰过的方法,在多线程执行的过程中,程序依次输出递增3的数字

 import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Synchronization implements Runnable {
private static int currentCount = 0;
synchronized void printAdd() {
currentCount++;
Thread.yield();
currentCount++;
Thread.yield();
currentCount++;
System.out.println(currentCount);
}
@Override
public void run() {
printAdd();
}
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
Synchronization test = new Synchronization();
for(int i = 0; i < 100; i++) {
exec.execute(test);
}
exec.shutdown();
}
}

(2)与之相对应的未用synchronized修饰过的方法,在多线程执行的过程中,程序会输出没有规律的数字

 import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Synchronization implements Runnable {
private static int currentCount = 0;
void printAdd() {
currentCount++;
Thread.yield();
currentCount++;
Thread.yield();
currentCount++;
System.out.println(currentCount);
}
@Override
public void run() {
printAdd();
}
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
Synchronization test = new Synchronization();
for(int i = 0; i < 100; i++) {
exec.execute(test);
}
exec.shutdown();
}
}

2.synchronized对于类静态成员方法的修饰

与对象相同,Java的每个类也有一个锁,所以我们可以通过将静态方法用synchronized修饰来控制其对于静态共享资源的访问。

三、Lock的使用

在上面的利用synchronized进行同步的描述中,我们都是利用方法所在对象自身的锁来进行同步。除了这种方法之外,我们还可以用Java语言中内置的锁对象来进行显式的加锁。

Lock接口,便是Java语言在java.util.concurrent.locks包中为我们提供的显式锁。目前在该包中有三个Lock的实现(基于JDK 1.7),分别为ReentrantLock,ReentrantReadWriteLock.ReadLock,ReentrantReadWriteLock.WriteLock

Lock对象必须在程序中被显式的创建、锁定和释放。

例3:使用Lock实现多线程之间的同步

 import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class LockTest implements Runnable { private static int currentCount = 0;
Lock lock = new ReentrantLock();
void addCount() {
lock.lock();
try {
currentCount++;
Thread.yield();
currentCount++;
Thread.yield();
currentCount++;
System.out.println(currentCount);
} finally {
lock.unlock();
}
}
@Override
public void run() {
addCount();
}
public static void main(String[] args) {
ExecutorService exec = Executors.newCachedThreadPool();
LockTest test = new LockTest();
for(int i = 0; i < 100; i++) {
exec.execute(test);
}
exec.shutdown();
}
}

四、synchronized与Lock的对比

在我的理解中,synchronized修饰的方法,在检查到对象已经被加锁的情况后,会等待到该对象锁被释放;之后对对象进行加锁,进行自身方法的执行。

但是Lock则不是如此,Lock可以尝试获取锁一段时间,或者尝试获取锁最后失败,而synchronized方式则不可以。综合来说,采用Lock显式锁可以完成更多并发控制功能,但是其较synchronized麻烦许多,所以根据自身程序的需要可以视情况选择这两种同步方法。

五、总结

本篇文章是简单的介绍了synchronized 及Lock的使用,Lock的高级使用将在下一篇文章进行介绍。小弟才疏学浅,如有错误,请多指出。

Java多线程编程(四)—浅谈synchronized与lock的更多相关文章

  1. Java多线程之线程同步【synchronized、Lock、volatitle】

    线程同步 线程同步:当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多. ...

  2. Java多线程编程实战指南(核心篇)读书笔记(四)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76690961冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...

  3. Java多线程编程详解

    转自:http://programming.iteye.com/blog/158568 线程的同步 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Ja ...

  4. Java多线程编程核心技术(三)多线程通信

    线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时 ...

  5. Java多线程编程核心技术(二)对象及变量的并发访问

    本文主要介绍Java多线程中的同步,也就是如何在Java语言中写出线程安全的程序,如何在Java语言中解决非线程安全的相关问题.阅读本文应该着重掌握如下技术点: synchronized对象监视器为O ...

  6. Java多线程编程核心技术(一)Java多线程技能

    1.进程和线程 一个程序就是一个进程,而一个程序中的多个任务则被称为线程. 进程是表示资源分配的基本单位,线程是进程中执行运算的最小单位,亦是调度运行的基本单位. 举个例子: 打开你的计算机上的任务管 ...

  7. Java多线程编程实战指南(核心篇)读书笔记(五)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76730459冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...

  8. Java多线程编程实战指南(核心篇)读书笔记(二)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76651408冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...

  9. Java多线程学习(二)synchronized关键字(2)

    转载请备注地址:https://blog.csdn.net/qq_34337272/article/details/79670775 系列文章传送门: Java多线程学习(一)Java多线程入门 Ja ...

随机推荐

  1. UVa 10473 - Simple Base Conversion

    题目大意:十进制与十六进制之间的相互转换. #include <cstdio> int main() { #ifdef LOCAL freopen("in", &quo ...

  2. 【蓝牙数据采集模块】-02-Sensor Controller 编写CC2650STK外设驱动

    上次说到把所有的传感器模块在Sensor Controller中实现读写,并封装驱动. 先来看一下CC2650STK的原理图 用红色方框标记的DIO_0~DIO_7, DIO_23~DIO_30是可以 ...

  3. C++中vector 容器的基本操作

    vector是一种简单高效的容器,具有自动内存管理功能.对于大小为n的vector容器,它的元素下标是0~n-1. vector有二个重要方法:     begin(): 返回首元素位置的迭代器.   ...

  4. html 5 本地数据库(Web Sql Database)核心方法openDatabase、transaction、executeSql 详解

    Web SQL数据库API实际上不是HTML5规范的组成部分,而是单独的规范.它通过一套API来操纵客户端的数据库.Safari.Chrome. Firefox.Opera等主流浏览器都已经支持Web ...

  5. js原生设计模式——8单例模式之简约版属性样式方法库

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8&qu ...

  6. MFC中在基于对话框的窗体中使用CFileDialog导致菜单栏变灰的解决方案

    CSDN的博客编辑器实在是难用……转战博客园 直接把CSDN发的搬过来了 ————————————————————————————我是分割线———————————————————————————— 第 ...

  7. spring mvc 入门示例

    classpath <?xml version="1.0" encoding="UTF-8"?> <classpath> <cla ...

  8. springmvc java.lang.NoSuchMethodError: com.fasterxml.jackson.core.JsonFactory.requiresPropertyOrdering()Z

    在hibernate spring springMVC整合的时候出现下面的情况: WARNING: Exception encountered during context initializatio ...

  9. Java各种工具下载

    http://yunpan.cn/cyUzqFTu8pEER  提取码 355c  myeclipse2013 http://yunpan.cn/cyUzPi7nC8Z9S  提取码 fc4b  my ...

  10. zstuoj 4243

    牛吃草 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 441  Solved: 139 Description 农夫有一个长满草的(x0, y0)为圆心 ...