在多线程程序执行过程中,可能会涉及到两个或者多个线程试图同一时候訪问同一个资源。为了防止这样的情况的发生,必须在线程使用共享资源时给资源“上锁”,以阻挡其他线程的訪问。

而这样的机制也经常被称为相互排斥量。本文主要介绍它的两种方式synchronized和Lock 。

1、synchronized

当任务要运行被synchronizedkeyword保护的代码片段的时候,它会检查锁是否可用,然后获取锁。运行代码。释放锁。synchronized也有两种使用方法:

A、synchronized方法

import java.util.concurrent.*;
import java.util.*; public class ThreadTest implements Runnable {
public synchronized void run() { //声明方式
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
public static void main(String[] args) {
ThreadTest t = new ThreadTest();
Thread t1 = new Thread(t, "A");
Thread t2 = new Thread(t, "B");
t1.start();
t2.start();
}
}/*
* Output: A0 A1 A2 A3 A4 B0 B1 B2 B3 B4
*/// :~

要注意的是,全部对象都自己主动含有单一的锁(也称为监视器)。所以当ThreadTest对象调用synchronized方法时,此对象被加锁,这意味着。其它线程不能调用此对象的全部synchronized方法。
可是假设把一个复杂的方法声明为synchronized,会减少程序执行的效率,所以synchronized块是非常好的解决方法。

B、synchronized块

import java.util.concurrent.*;
import java.util.*; public class ThreadTest {
public void g() {
synchronized (this) { //声明方式
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
} public static void main(String[] args) {
final ThreadTest t = new ThreadTest();
Thread t1 = new Thread(new Runnable() {
public void run() {
t.g();
}
}, "A");
Thread t2 = new Thread(new Runnable() {
public void run() {
t.g();
}
}, "B");
t1.start();
t2.start();
}
}
/*
* Output: A0 A1 A2 A3 A4 B0 B1 B2 B3 B4
*/// :~

当一个线程在訪问object对象的一个synchronized(this)同步代码块时,其他线程仍然能够訪问此对象的非同步代码块。

当然假设不是同一个对象

,synchronized是无法实现相互排斥的。以下是第一句话的代码:

import java.util.concurrent.*;
import java.util.*; public class ThreadTest {
public void g() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
} public void h() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + i);
}
}
public static void main(String[] args) {
final ThreadTest t = new ThreadTest();
Thread t1 = new Thread(new Runnable() {
public void run() {
t.g();
}
}, "A");
Thread t2 = new Thread(new Runnable() {
public void run() {
t.h();
}
}, "B");
t1.start();
t2.start();
}
}
/*
* Output:A0 B0 A1 B1 A2 B2 A3 B3 A4 B4
*/// :~

2、Lock

Lock和synchronized的差别就是:

synchronized:当A和B同一时候要訪问C资源,而A获得了对象C的锁。B将一直等待A释放对C的锁,不能被中断。

Lock:B等待一定时间后,A还不释放C,B就会中断等待。

它的基本使用方法:

Lock l = new ReentrantLock();
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}

从代码也能够看出,l.unlock()在finally{}中。这表示终于会被解锁。

3、volatile

用volatile修饰的变量。线程在每次使用变量的时候,都会读取变量改动后的最的值,它能避免因编译器优化导致的读值不准确,

然而它非常easy被误用。

比方仅仅使用volatile变量来实现的累加器,无法得到正确结果。由于JAVA中的自增操作++,

并非原子性操作,在自增过程中还是出现了多线程间的交互。

JAVA学习笔记 -- 多线程之共享资源的更多相关文章

  1. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  2. Java学习笔记-多线程-创建线程的方式

    创建线程 创建线程的方式: 继承java.lang.Thread 实现java.lang.Runnable接口 所有的线程对象都是Thead及其子类的实例 每个线程完成一定的任务,其实就是一段顺序执行 ...

  3. java学习笔记 --- 多线程(线程安全问题——同步代码块)

    1.导致出现安全问题的原因: A:是否是多线程环境 B:是否有共享数据 C:是否有多条语句操作共享数据 2.解决线程安全问题方法: 同步代码块: synchronized(对象){ 需要同步的代码; ...

  4. java学习笔记 --- 多线程(多线程的创建方式)

    1.创建多线程方式1——继承Thread类. 步骤:  A:自定义类MyThread继承Thread类.  B:MyThread类里面重写run()? 为什么是run()方法呢? C:创建对象 D:启 ...

  5. 0041 Java学习笔记-多线程-线程池、ForkJoinPool、ThreadLocal

    什么是线程池 创建线程,因为涉及到跟操作系统交互,比较耗费资源.如果要创建大量的线程,而每个线程的生存期又很短,这时候就应该使用线程池了,就像数据库的连接池一样,预先开启一定数量的线程,有任务了就将任 ...

  6. 0040 Java学习笔记-多线程-线程run()方法中的异常

    run()与异常 不管是Threade还是Runnable的run()方法都没有定义抛出异常,也就是说一条线程内部发生的checked异常,必须也只能在内部用try-catch处理掉,不能往外抛,因为 ...

  7. 0039 Java学习笔记-多线程-线程控制、线程组

    join线程 假如A线程要B线程去完成一项任务,在B线程完成返回之前,不进行下一步执行,那么就可以调用B线程的join()方法 join()方法的重载: join():等待不限时间 join(long ...

  8. java学习笔记 --- 多线程(1)

    1:要想了解多线程,必须先了解线程,而要想了解线程,必须先了解进程,因为线程是依赖于进程而存在. 2:什么是进程? 通过任务管理器我们就看到了进程的存在. 而通过观察,我们发现只有运行的程序才会出现进 ...

  9. 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题

    调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...

随机推荐

  1. HTML5-坦克大战一画出敌人坦克并让自己的坦克可以发子弹的功能(二)

    上一篇博客只画出了,一个坦克,并让其可以上下左右移动,这篇博客将画出敌人的坦克,并让自己的坦克可以发子弹,但是还不是尽善尽美,还有一些问题,将会在下篇博客说明: html代码: <!DOCTYP ...

  2. [ 总结 ] Linux下两种常用的双网卡绑定

    1. mode=0 (round-robin) 链路聚合:将两个或者更多数据信道结合成一个单一的信道,该信道以一个更高带宽的逻辑链路出现,链路聚合一般用来连接一个或多个带宽需求量大的设备,链路聚合是指 ...

  3. 删除某个ros包之后catkin_make冒错

    CMake Error at /home/ubuntu/Workspaces/rosProject/workspace1/devel/share/costmap_2d/cmake/costmap_2d ...

  4. 【hdoj_1050】Moving Tables

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1050 题意为: 为了叙述方便,把一个房间里面的桌子移动到另一个房间称为一个移动,给出若干个要求完成的移 ...

  5. Ajax 生成流文件下载(实现代码)

    // 绑定导出按钮    $("#btnExport").clickCheckLogin(function () { var form = $("<form> ...

  6. .NET Core on Raspberry Pi

    原文地址:传送门 .NET Core on Raspberry Pi Arm32 builds are available as community supported builds for .NET ...

  7. unity制作简单血条

    学习Unity已经10天了,也没发现有什么长进,真的急.昨天仿着官方Demo做了个射击游戏轮廓,其中需要给每个怪做一个血条. 搜了一些,挺复杂的,用NGUI或者UGUI,外加很长的代码...不过还是找 ...

  8. linux 批量替换所有文件中包含的字符串

    sed -i "s/原来字符串/新字符串/g" `grep 原来字符串 -rl .` 格式: sed -i "s/查找字段/替换字段/g" `grep 查找字段 ...

  9. System Center VMM请注意不同语言版本的差异

    在私有云的项目中,经常需要判断System Center一些组件的连接是否OK. 我这里有开发,和测试两个环境,开发是英文版的System Center VMM,测试用的是中文版的System Cen ...

  10. LCIS最长公共上升子序列

    最长公共上升子序列LCIS,如字面意思,就是在对于两个数列A和B的最长的单调递增的公共子序列. 这道题目是LCS和LIS的综合. 在LIS中,我们通过两重循环枚举当序列以当前位置为结尾时,A序列中当前 ...