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

而这样的机制也经常被称为相互排斥量。本文主要介绍它的两种方式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. 【SQL】数据库更新

    1.插入 INSERT INTO R(A1,A2,...An) VALUES(v1, v2, ...,vn) 如果插入了所有属性,并且按照定义的顺序给出,可以省略(A1,A2,...An) 可以只插入 ...

  2. 《Java编程思想》笔记 第十七章 容器深入研究

    1 容器分类 容器分为Collection集合类,和Map键值对类2种 使用最多的就是第三层的容器类,其实在第三层之上还有一层Abstract 抽象类,如果要实现自己的集合类,可以继承Abstract ...

  3. HDU-3320

    Alice’s Cube Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

  4. ubuntu 16.04安装redis群集zz

    之前有文章,写明了如何安装redis.这里,进行群集配置. 创建Redis配置目录 /etc/redis: $ sudo mkdir /etc/redis/redis_cluster $cd /etc ...

  5. centos 查看 arp

    yum install tcpdump -y tcpdump arp :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: :: ...

  6. Retrying Operations using Spring's RetryTemplate

    If your application is using Spring then it is easier to use the Spring Framework's RetryTemplate. T ...

  7. 简单DP【p2642】双子序列最大和

    Description 给定一个长度为n的整数序列,要求从中选出两个连续子序列,使得这两个连续子序列的序列和之和最大,最终只需输出最大和.一个连续子序列的和为该子序列中所有数之和.每个连续子序列的最小 ...

  8. ( 转 ) mysql 实战 or、in与union all 的查询效率

    OR.in和union all 查询效率到底哪个快. 网上很多的声音都是说union all 快于 or.in,因为or.in会导致全表扫描,他们给出了很多的实例. 但真的union all真的快于o ...

  9. java中的3大特性之继承

    继承的特点:继承父类的属性和方法.单继承(多层继承)c++里的继承是多继承 特性 :方法的复写(重写) java中的继承和OC中一样. 比如:人可以养狗; 人---->狗 :整体和部分(拥有)关 ...

  10. [Atcoder Grand Contest 002] Tutorial

    Link: AGC002 传送门 A: …… #include <bits/stdc++.h> using namespace std; int a,b; int main() { sca ...