您的位置:首页 > Web前端

effect java 学习摘要(8) - 并发

2017-08-17 23:54 489 查看

同步访问共享的可变数据

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, 没必要继续使用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: