一、同步
1.1、为什么需要同步
同步是在多线程访问共享资源的情况下发生的,比如有A、B两个线程同时访问共享资源C, 并且都需要对C进行操作。这时如果没有同步机制,将导致一系列的问题。
1.2、同步的方式
java中同步方式包括以下几种方式:
1.2.1 synchronized关键字
synchronized是JVM提供的一个便捷的同步方式。每个对象都自动含有单一的锁,JVM会负责跟踪每个 对象加锁的情况。当一个对象没有加锁时,可以调用该对象的synchronized方法或者synchronized代码 块。
当C对象被A线程加锁,A线程可以访问C对象的其他方法,B线程只能等待C的锁释放后才能访问 C的synchronized方法或synchronized代码块。但是B线程能访问C的非synchronized代码块。
synchronized保证线程A退出C对象的方法时,B线程看到C对象的最新状态。
1.2.2 volatile关键字
volatile 修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。因此A线程修改被volatile修饰的变量时,B线程能够及时感应。一般用volatile修饰控制状态,比如stop、running等。
1.2.3 wait、notify机制
wait、notify必须配合synchronized关键字使用。
public class MyThread implements Runnable { private String name; private Object prev; private Object self; private MyThread(String name, Object prev, Object self) { this.name = name; this.prev = prev; this.self = self; } public void run() { int count = 10; while (count > 0) { synchronized (prev) { synchronized (self) { count--; System.out.println(name +" release lock "+ self); self.notify(); } try { System.out.println(name +" wait lock "+prev); prev.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws Exception { Object a = new Object(); Object b = new Object(); Object c = new Object(); MyThread pa = new MyThread("A", c, a); MyThread pb = new MyThread("B", a, b); MyThread pc = new MyThread("C", b, c); new Thread(pa).start(); new Thread(pb).start(); new Thread(pc).start(); } }
wait、notify常用限制线程的执行顺序。wait会释放获取的C对象锁,等其他线程调用了C 对象的notify方法后,JVM会选择一个等待C对象锁的线程继续执行。
二、Thread.sleep()
Thread.sleep与wait的区别在于,sleep不会释放对象锁。
三、ThreadLocal
ThreadLocal目的是线程隔离,每个线程有自己的对象副本。而不是共享对象。