目录
1.安全问题的产生
2.同步:synchronized
3.并发中的三个概念
4.happens-before原则
5.修饰符:volatile
1.安全问题的产生
如果我们想实现这样一个功能:利用线程并发模拟多个网点售同一种票.例:
public class ThreadDemo { public static void main(String[] args) { Ticket ticket = new Ticket(); new Thread(ticket).start(); new Thread(ticket).start(); new Thread(ticket).start(); } } class Ticket implements Runnable { final Random r = new Random(); private int num = 10; @Override public void run() { while (true) { if (num > 0) { try { Thread.sleep(r.nextInt(100)); } catch (InterruptedException e) { } System.out.println(Thread.currentThread().getName() + "..." + num--); } else { break; } } } }
在运行结果中,输出了0和-1,一共买了12张票!
由于每个线程执行的过程是不可控的,多个线程同时访问一个资源(本例中的num)时,会导致程序运行结果并不是想看到的结果,便会产生线程安全问题,这个资源被称为共享资源.
2.同步
2.1synchronized
基本上所有的并发模式在解决线程安全问题时,都采用"序列化访问临界资源"的方案,即同一时刻只能有一个线程访问共享资源,也称作同步互斥访问.通常是在访问临界资源的代码前面加上一个锁,当访问完临界资源后释放锁,让其他线程继续访问.java提供了synchronized关键字实现同步互斥访问,synchronized既可以修饰代码块,也可以用来修饰方法.
每一个对象都拥有一个锁标记(monitor),也称为监视器,线程只有获取了该对象的锁才能访问.使用synchronized关键字来标记一个方法或者代码块,当某个线程调用该对象的synchronized方法或者访问synchronized代码块时,这个线程便获得了该对象的锁,其他线程暂时无法访问这个方法,只有等待这个方法执行完毕或者代码块执行完毕,这个线程才会释放该对象的锁,其他线程才能执行这个方法或者代码块.
2.2同步块
public class ThreadDemo { public static void main(String[] args) { Ticket ticket = new Ticket(); new Thread(ticket).start(); new Thread(ticket).start(); new Thread(ticket).start(); } } class Ticket implements Runnable { final Random r = new Random(); private int num = 10; private Object obj=new Object(); @Override public void run() { while (true) { synchronized(obj){ if (num > 0) { try { Thread.sleep(r.nextInt(100)); } catch (InterruptedException e) { } System.out.println(Thread.currentThread().getName() + "..." + num--); } else { break; } } } } }
2.3同步方法
public class Test { public static void main(String[] args) { Ticket ticket = new Ticket(); new Thread(ticket).start(); new Thread(ticket).start(); new Thread(ticket).start(); } } class Ticket implements Runnable { final Random r = new Random(); private int num = 10; private boolean isEmpty = false; @Override public void run() { while (!isEmpty) { sell(); } } public synchronized void sell() { if (num > 0) { try { Thread.sleep(r.nextInt(100)); } catch (InterruptedException e) { } System.out .println(Thread.currentThread().getName() + "..." + num--); } else { isEmpty = true; } } }
当一个线程正在访问一个对象的synchronized方法,那么其他线程不能访问该对象的其他synchronized方法,但是能访问该对象的非synchronized方法;如果一个线程A需要访问对象object1的synchronized方法fun1,另外一个线程B需要访问对象object2的synchronized方法fun1,即使object1和object2是同一类型,因为他们访问的是不同的对象,不会产生线程安全问题.同步方法是同步块的简写,效率相对较低.
2.4类的锁
每个类也会有一个锁,它可以用来控制对static数据成员的并发访问.改进后线程安全的单例模式:
public class Single { private static Single instance; private Single() { } public static Single getInstance() { if (instance == null) {// 解决了效率问题 synchronized (Test.class) {// 解决了并发安全 if (instance == null) { instance = new Single(); } } } return instance; } }
3.并发中的三个概念
3.1原子性 即一个操作或者多个操作要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行.java内存模型只保证了基本读取和赋值是原子性操作.由于synchronized和Lock能够保证任一时刻只有一个线程执行该代码块,保证了大范围的原子性.
3.2可见性
当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值.java中通过volatile修饰的变量可以保证可见性.
3.3有序性
程序执行的顺序按照代码的先后顺序执行.
指令重排序:处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的.
java内存模型具备一些先天的"有序性",不需要通过任何手段就能够得到保证的有序性,通常也称为 happens-before原则.如果两个操作的执行次序无法从happens-before原则推导出来,那么它们就不能保证它们的有序性,虚拟机可以随意地对它们进行重排序.
4.happens-before原则
1)程序次序规则:一个线程内按照代码顺序,在前面的操作先行发生于在后面的操作
2)锁定规则:一个unLock操作先行发生于后面对同一个锁的lock操作
3)volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作
4)传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C
5)线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作
6)线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
7)线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行
8)对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始
5.修饰符:volatile
使用volatile修饰变量,保证其可见性并且禁止进行指令重排序.要实现线程安全必须保证变量是独立的,且对变量的操作是原子性的.volatile一般用于状态标志量.
相关推荐
Java并发集合框架(java.util.concurrent包)提供了线程安全的数据结构,如ConcurrentHashMap、CopyOnWriteArrayList、ConcurrentLinkedQueue等,它们在多线程环境下表现优秀,避免了传统的同步代码块带来的性能开销...
Java并发工具类库(java.util.concurrent)是并发编程中的另一个重要主题,包括Atomic类(提供原子操作)、Semaphore(信号量)、CountDownLatch(计数器门锁)、CyclicBarrier(循环栅栏)和Exchanger(交换器)等...
这些API是Java并发编程的核心,书中会详细解析它们的使用方法和应用场景。 3. **线程安全**:线程安全是并发编程中的重要主题,书中会探讨各种线程安全的实现策略,如使用`synchronized`关键字、`volatile`变量、`...
《Java并发编程:设计原则与模式2中文版》是一本深度探讨Java开发中并发编程的专著,旨在帮助开发者理解和掌握在多线程环境下编写高效、安全、可维护的代码。这本书涵盖了Java并发编程的核心概念、最佳实践以及常用...
### Java 并发基石:同步机制的全面解析 #### Java 的并发编程背景 Java作为一种广泛应用的编程语言,自1995年由Sun Microsystems(现属于Oracle公司)发布以来,已经发展成为一种支持跨平台性、面向对象编程、多...
1. **并发基础**:首先,书中会介绍并发编程的基本概念,如线程、进程、同步与通信机制,以及Java中的线程API,如`Thread`类和`Runnable`接口。 2. **线程管理**:讨论如何创建、启动、停止和控制线程,包括线程池...
《Java并发编程:设计原则与模式(第二版)》是一本深入探讨Java平台上的多线程和并发编程的权威著作。这本书旨在帮助开发者理解和掌握如何有效地编写可扩展且高效的并发程序。以下是书中涵盖的一些关键知识点: 1....
#### 一、Java并发概述 自Java诞生之初,其设计者就赋予了该语言强大的并发处理能力。Java语言内置了对线程和锁的支持,这使得开发者能够轻松地编写多线程应用程序。本文旨在帮助Java开发者深入理解并发的核心概念...
In this chapter, we will cover: 1.Synchronizing a method; 2.Arranging independent attributes in synchronized classes; 3.Using conditions in synchronized code; 4.Synchronizing a block of code with a ...
AQS是处理线程同步问题的高效工具,是Java并发编程中的核心。文章首先简要介绍了并发编程领域的先驱Doug Lea。重点在于ReentrantLock的分析,它是基于AQS实现的互斥锁。相比synchronized,它提供了更多特性,如手动...
总而言之,《Java并发编程:设计原则与模式(第二版)》这本书全面覆盖了Java并发编程的各个方面,无论是线程基础知识,还是高级的并发控制和同步策略,都有详尽的解析和实例。通过学习,开发者将能够编写出更加高效...
为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器、并发容器、阻塞队列、Synchronizer(比如CountDownLatch)。我们来讨论下同步容器。 一.为什么会出现同步容器? 在...
《Java并发编程:设计原则与模式》是一本深入探讨Java多线程编程的权威书籍,由Doug Lea撰写,第二版全面涵盖了Java并发处理的各个方面。这本书不仅提供了丰富的理论知识,还介绍了实战中的设计原则和模式,对于Java...
5. **J.U.C框架**:Java并发 utilities (J.U.C) 框架是Java并发编程的重要组成部分,书中会介绍如何利用这个框架来提升并发性能和代码的可读性。 6. **性能调优**:在高并发场景下,性能优化是必不可少的。可能涵盖...
本资料“Java并发编程:设计原则与模式”深入探讨了这些关键主题。 首先,我们需要理解Java并发编程的基础概念。Java中的并发是通过线程实现的,线程是程序执行的最小单位。Java提供了多种创建和管理线程的方法,如...
java并发方面的两大名著之一。读者将通过使用java.lang.thread类、synchronized和volatile关键字,以及wait、notify和notifyall方法,学习如何初始化、控制和协调并发操作。此外,本书还提供了有关并发编程的全方位...
3. **并发容器**:书中深入讨论了Java并发容器,如ArrayList、LinkedList、HashSet、HashMap以及并发优化过的ConcurrentHashMap、CopyOnWriteArrayList和CopyOnWriteArraySet等,以及它们在多线程环境下的性能和使用...
书中会首先介绍Java并发编程的基础知识,包括线程的创建和运行,同步机制的基本用法,以及Java内存模型的相关概念。随着章节的深入,作者可能会更深入地讲解Java提供的并发工具,例如锁、原子变量、线程池、以及并发...
通过阅读《Java并发编程的艺术》这本书,开发者不仅可以掌握Java并发编程的基础知识,还能了解到一些高级特性和技巧,从而在实际开发中游刃有余。同时,附带的源码将有助于加深理解,提供实际操作的机会。