同步访问共享的可变数据
synchronized : 可以保证在同一时刻,只有一个线程可以执行某一个方法, 或者某一个代码块.
多线程访问, 可能会导致同一对象状态发生变化. 同步 可以使多线程看到由同一个锁保护的之前所有的修改效果.
非long或double类型的变量, 读写操作一个变量是原子的
在线程之间进行可靠的通信, 也为了互斥访问, 同步是必要的.
不要使用 Thread.stop() , 要阻止一个线程妨碍另一个线程 ,正确做法如下 :
public class StopThread { public static boolean stopRequested; private static synchronized void requestStop() { stopRequested = true; } public static synchronized boolean stopRequested() { return stopRequested; } public void stopThread() throws InterruptedException { Thread backgroundThread = new Thread(new Runnable() { @Override public void run() { int i = 0; while (!stopRequested()) { i++; } } }); backgroundThread.start(); TimeUnit.SECONDS.sleep(1); requestStop(); } }
如果读写操作都没有进行同步 , 那么同步就不会起作用.
public class StopThread { public static volatile boolean stopRequested; public void stopThread() throws InterruptedException { Thread backgroundThread = new Thread(new Runnable() { @Override public void run() { int i = 0; while (!stopRequested) { i++; } } }); backgroundThread.start(); TimeUnit.SECONDS.sleep(1); stopRequested = true; } }
多个线程共享可变数据的时候, 每个读或者写数据的线程都必须执行同步
避免过度同步
- 共享数据类型,需要使用线程安全的数据结构 , 例如 : CopyOnWriteArrayList
executor和task优先于线程
- 尽量避免自己编写工作队列, 尽量不要直接使用线程, 使用java提供的executor线程池
并发工具优先于wait和notify
线程高级工具 :
- Executor Framework
- 并发集合
- 同步器 : CountDownLatch 和 Semaphore
public class Synchronizer { final Executor executor = Executors.newSingleThreadExecutor(); final CountDownLatch ready = new CountDownLatch(3); final CountDownLatch start = new CountDownLatch(1); final CountDownLatch done = new CountDownLatch(3); final Runnable runnable = new Runnable() { @Override public void run() { //do nothing } }; private long test() throws InterruptedException { for (int i = 0;i < 3; i++) { executor.execute(new Runnable() { @Override public void run() { ready.countDown(); try { start.await(); runnable.run(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { done.countDown(); } } }); } ready.await(); long startNanos = System.nanoTime(); start.countDown(); done.await(); return System.nanoTime() - startNanos; } }
- 调用wait方法,应当用循环之内调用 , 永远不要在循环外调用
- 优先使用notifyAll , 当只有一个线程被唤醒才使用notify
延迟初始化
lazy initializition holder class 模式 : 常见用于单例模式
private static class FieldHolder { static final FieldType field = computeFieldValue(); } static FieldType getFieldType() { return FieldHolder.field; }
避免使用线程组
- ThreadGroup 已经为过时的API, 没必要继续使用