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

而这样的机制也经常被称为相互排斥量。本文主要介绍它的两种方式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. 【转】spring 装配Bean中构造参数的注入

    转载自:http://www.bianceng.cn/Programming/Java/201307/37027.htm spring 装配Bean中构造参数的注入 spring装配bean中还有一种 ...

  2. USACO 2012 Feb Cow Coupons

    2590: [Usaco2012 Feb]Cow Coupons Time Limit: 10 Sec Memory Limit: 128 MB Submit: 349 Solved: 181 [Su ...

  3. 《Java编程思想》笔记 第十五章 泛型

    1 泛型 “泛型”意思就是适用于许多类型. 使用泛型的目的之一: 指定容器持有什么类型,让编译器确保正确性,而不是在运行期发现错误. 这个容器可以看成是有其他类型对象作为成员的类,而不单单只是JDK中 ...

  4. PostgreSQL9.6.3的REDIS测试

    安装redis_fdwcd /usr/local/srcgit clone https://github.com/pg-redis-fdw/redis_fdw.gitcd redis_fdw/git ...

  5. ES6的特性(译+注解)

    介绍 ES6,也叫ECMAScript2015(以下统称ES6),是ECMAScript标准的最新版本.这个标准在2015年6月份被正式批准.ES6是js语言很有意义的一次更新,也是2009年ES5被 ...

  6. 解决nextjs部署到now上之后出现的“Unable to import module 'now__launcher'”错误

    解决nextjs部署到now上之后出现的“Unable to import module 'now__launcher'”错误 这个错误是由于在next.config.js中直接引用了withLess ...

  7. 51nod 多重背包问题(动态规划)

    多重背包问题 一个背包,承量有限为W,有n种物体,第i种物体,价值Vi,占用重量为 Wi,且有Ci件,选择物品若干放入背包,使得总重量不超过背包的承重.总价值最大? 输入 第1行,2个整数,N和W中间 ...

  8. Cent OS 运行 Cuberite

    Cuberite 是一个轻量级的Minecraft服务端,由C++编写,性能比Mojang等等用java写的高很多. 在腾讯云的最低端VPS上,用Spigot建服的话,从主世界传送到下界用时要五六秒的 ...

  9. 转:mysql group by 用法解析(详细)

    group by 用法解析 group by语法可以根据给定数据列的每个成员对查询结果进行分组统计,最终得到一个分组汇总表. SELECT子句中的列名必须为分组列或列函数.列函数对于GROUP BY子 ...

  10. POJ 3260 The Fewest Coins(背包问题)

    [题目链接] http://poj.org/problem?id=3260 [题目大意] 给出你拥有的货币种类和每种的数量,商店拥有的货币数量是无限的, 问你买一个价值为m的物品,最少的货币流通数量为 ...