一、共享资源竞争问题

在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. Myeclipse SVN 修改用户名和密码

    转自:http://blog.csdn.net/chow__zh/article/details/7731497 解决方案: 在Eclipse使用SVN的过程中大多数人往往习惯把访问SVN的用户名密码 ...

  2. Maven deploy时报Fatal error compiling: tools.jar not found错误的问题处理

    摘自:http://blog.csdn.net/achilles12345/article/details/19046061 在Eclipse环境下,使用Maven进行deploy时发现报了该错误:F ...

  3. beforeunload

    <!DOCTYPE html> <html> <head> <title>BeforeUnload Event Example</title> ...

  4. 扫码JSP

    扫码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.o ...

  5. delphi 获得memo,Richedit焦点所在行

    procedure TForm1.Button1Click(Sender: TObject); var i:Integer; begin i:=SendMessage(Richedit1.handle ...

  6. HTML模块化:使用HTML5 Boilerplate模板

    HTML5 Boilerplate 是一个由 Paul Irish(Google Chrome 开发人员.jQuery 项目成员.Modernizr 作者.yayQuery 播客主持人)主导的“前端开 ...

  7. JavaSE学习总结(一)——Java基础

    一.Java是什么 Java 是由 Sun Microsystems 在 1995 年首先发布的编程语言和计算平台.Java 是一项用于开发应用程序的技术,可以让 Web 变得更有意思和更实用.有许多 ...

  8. Java 获取url参数

    1. 方式一:使用HttpServletRequest对象 String id = arg0.getParameter("id"); mv.addObject("id&q ...

  9. Spring mvc基本原理

    http://blog.csdn.net/xtu_xiaoxin/article/details/8796499 http://www.cnblogs.com/wawlian/archive/2012 ...

  10. cvc-complex-type.2.4.c: The matching wildcard...

    在家里的电脑好好的,在单位的就不行,需要把web app libraties提到 最前面,然后clean一下项目