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

而这样的机制也经常被称为相互排斥量。本文主要介绍它的两种方式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. shell里面比较大小

     #!/bin/bashif [ $1 -gt $2 ]then echo "$1>$2"else echo "$2>$1"fi# 数字判断一些命令 ...

  2. GenericAPIView类与几个扩展类的综合使用

    五个扩展类 扩展类 作用 封装的方法 状态码(成功,失败) ListModelMixin 查询多条数据 list 200 CreateModelMixin 新增一条数据 create 201,400 ...

  3. bootstrapValidator关于verbose需要优化的地方

    开发中需要用到bootstrapValidator的配置verbose:false,达到当前验证不通过不往下在验证的效果 问题: 当前字段需要remote验证时,此配置无效,原因在于remote是异步 ...

  4. Selenium2+python自动化-窗口多标签处理方法总结(转载)

    本篇转自博客:上海-小T 原文地址:https://i.cnblogs.com/EditArticles.aspx?opt=1 我们在用Selenium遇到多个浏览器窗口或单个浏览器多个标签(Tab) ...

  5. [loj#115] 无源汇有上下界可行流 网络流

    #115. 无源汇有上下界可行流 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统计讨论测试数据   题 ...

  6. Vue 不使用Vuex的情况下进行状态管理

    在封装自己的Vue ui库的时候,往往要封装一些比较复杂的组件,比如说table,form之类.这些组件由于功能繁杂,还涉及到子组件嵌套及通信,如果没有一套状态管理方案的话很容易导致代码难以阅读.难以 ...

  7. [xampp] ubuntu终端连接xampp的mysql

    /opt/lampp/bin/mysql -u root

  8. thinkphp函数学习(1)——header, get_magic_quotes_gpc, array_map, stripslashes, stripslashes_deep

    1. header 相关语句 header('Content-type: text/html; charset=utf-8'); // 因为这是在TP的入口文件中,所以每个页面返回的http head ...

  9. Codeforces 1023 A.Single Wildcard Pattern Matching-匹配字符 (Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Fi)

    Codeforces Round #504 (rated, Div. 1 + Div. 2, based on VK Cup 2018 Final) A. Single Wildcard Patter ...

  10. POJ 3264 Balanced Lineup 【线段树/区间最值差】

    Balanced Lineup Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 62103 Accepted: 29005 Cas ...