一、共享资源竞争问题

在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. arcgis_server_address_note

    arcgis server api下载地址 https://developers.arcgis.com/downloads/ 先前版本的帮助 http://resources.arcgis.com/z ...

  2. 关于ThreadLocal和一般的线程同步的详细解释

    http://blog.csdn.net/lufeng20/article/details/24314381

  3. C++风格写判断某年某月某日是一年的第几天

    初学C++,在结构体中写函数及一些C++语言需要的一些格式 看代码 #include<iostream>#include<cstdio>using namespace std; ...

  4. SVG的text使用

    SVG的text使用: 参考:http://www.docin.com/p-7393979.html <%@ page language="java" contentType ...

  5. java算法 蓝桥杯 高精度加法

    问题描述 在C/C++语言中,整型所能表示的范围一般为-231到231(大约21亿),即使long long型,一般也只能表示到-263到263.要想计算更加规模的数,就要用软件来扩展了,比如用数组或 ...

  6. # C#不登录电脑启动程序

    我们知道开机自启动程序如果在用户不登录的情况下是不启动的,但是服务类程序是可以跨过用户登录启动的,例如IIS服务,SQL服务.如果我们已经写好了桌面应用程序,又希望他开机自启动,那就需要借助系统服务在 ...

  7. 转:Spring FactoryBean源码浅析

    http://blog.csdn.net/java2000_wl/article/details/7410714 在Spring BeanFactory容器中管理两种bean 1.标准Java Bea ...

  8. eNSP仿真学习,网络入门!

    为了简单的认识Internet的框架的整体结构,简单学习华为的eNSP软件来高度模拟仿真网络框架!(华为和思科公司都发布了自己的网络设备仿真软件,当然我就用国产的吧~) 华为官方的eNSP学习论坛网站 ...

  9. asp.net core mvc权限控制:权限控制介绍

    在进行业务软件开发的时候,都会涉及到权限控制的问题,asp.net core mvc提供了相关特性. 在具体介绍使用方法前,我们需要先了解几个概念: 1,claim:英文翻译过来是声明的意思,一个cl ...

  10. beautifulsoup 获取a(tag)的属性href

    一开始使用使用attrs(“href”) 出现错误TypeError: 'dict' object is not callable 由于attrs字典类型 atrrs["href" ...