您的位置:首页 > Web前端

Effective Java-学习笔记(10-11章)

2017-05-13 20:15 381 查看

并发

66.同步访问共享的可变数据

private static boolean isStop = true;

Thread myThread = new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while (isStop) {
i++;
Log.i("clp", "i=" + i);
}
}
});

myThread.start();

try {
Thread.sleep(1000);
} catch (Exception e) {

}
isStop = false;


上面的代码Thread的线程看不到isStop值的修改,所以会一直执行下去。

一种方式是添加volatile。private static volatile boolean isStop = true;

private static synchronized void requestStop() {
isStop = true;
}

private static synchronized boolean stopRequested() {
return isStop;
}

private static boolean isStop = false;

Thread myThread = new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while (!stopRequested()) {
i++;
Log.i("clp", "i=" + i);
}
}
});

myThread.start();

try {
Thread.sleep(1000);
} catch (Exception e) {

}
requestStop();


67.避免过度同步

1.在同步块中不要调用外来方法

RE:你不知道外来方法执行了什么操作

2.尽量减少同步块中代码的工作量

RE:在多核的设备上,这样会耗费性能(持续等待)

锁,是指当前线程持有的话,其他线程要想调用,需要等待当前线程的锁释放,但是如果当前线程执行到同步的代码,可以直接执行。

public class CldSyncUtil {

private static Object object = new Object();

public static String getName() {
synchronized (object) {//因为getFullName中的方法直接调用getName,是在同一个线程,所以可以直接使用
Log.i("clp", "a");
return "a";
}
}

public static String getFullName() {
synchronized (object) {
Log.i("clp", "b");
return "b" + getName();//调用同样需要同步锁的getName方法
}
}

}


for (int j = 0; j < 10; j++) {
Log.i("clp", CldSyncUtil.getFullName());
}


05-08 17:10:10.291 3473-3473/old.pkg.com.myapplicati I/clp: b
05-08 17:10:10.292 3473-3473/old.pkg.com.myapplicati I/clp: a
05-08 17:10:10.292 3473-3473/old.pkg.com.myapplicati I/clp: ba
05-08 17:10:10.292 3473-3473/old.pkg.com.myapplicati I/clp: b
05-08 17:10:10.292 3473-3473/old.pkg.com.myapplicati I/clp: a
05-08 17:10:10.292 3473-3473/old.pkg.com.myapplicati I/clp: ba


上面的这种写法,代码会顺序执行。因为第一次调用,会锁住对象,for循环后面的要等待。

public class CldSyncUtil {

private static Object object = new Object();

public static String getName() {
Log.i("clp", "getName thread=" + Thread.currentThread().getId());
synchronized (object) {//因为getFullName中的方法直接调用getName,是在同一个线程,所以可以直接使用
Log.i("clp", "a");
return "a";
}
}

public static String getFullName() {
Log.i("clp", "getFullName thread =" + Thread.currentThread().getId());
synchronized (object) {
Log.i("clp", "b");
return "b" + getName();//调用同样需要同步锁的getName方法
}
}

}


for (int j = 0; j < 5; j++) {
new Thread(new Runnable() {
@Override
public void run() {
Log.i("clp", CldSyncUtil.getFullName());
}
}).start();
}


05-08 17:26:20.159 4239-4256/old.pkg.com.myapplicati I/clp: getFullName thread =178
05-08 17:26:20.159 4239-4256/old.pkg.com.myapplicati I/clp: b thread =178
05-08 17:26:20.159 4239-4256/old.pkg.com.myapplicati I/clp: getName thread=178
05-08 17:26:20.159 4239-4256/old.pkg.com.myapplicati I/clp: a thread =178
05-08 17:26:20.161 4239-4255/old.pkg.com.myapplicati I/clp: getFullName thread =177
05-08 17:26:20.161 4239-4255/old.pkg.com.myapplicati I/clp: b thread =177
05-08 17:26:20.161 4239-4255/old.pkg.com.myapplicati I/clp: getName thread=177
05-08 17:26:20.161 4239-4255/old.pkg.com.myapplicati I/clp: a thread =177
05-08 17:26:20.168 4239-4259/old.pkg.com.myapplicati I/clp: getFullName thread =181
05-08 17:26:20.169 4239-4259/old.pkg.com.myapplicati I/clp: b thread =181
05-08 17:26:20.169 4239-4259/old.pkg.com.myapplicati I/clp: getName thread=181
05-08 17:26:20.169 4239-4259/old.pkg.com.myapplicati I/clp: a thread =181
05-08 17:26:20.169 4239-4257/old.pkg.com.myapplicati I/clp: getFullName thread =179
05-08 17:26:20.169 4239-4257/old.pkg.com.myapplicati I/clp: b thread =179
05-08 17:26:20.169 4239-4257/old.pkg.com.myapplicati I/clp: getName thread=179
05-08 17:26:20.169 4239-4257/old.pkg.com.myapplicati I/clp: a thread =179
05-08 17:26:20.172 4239-4258/old.pkg.com.myapplicati I/clp: getFullName thread =180
05-08 17:26:20.172 4239-4258/old.pkg.com.myapplicati I/clp: b thread =180
05-08 17:26:20.172 4239-4258/old.pkg.com.myapplicati I/clp: getName thread=180
05-08 17:26:20.172 4239-4258/old.pkg.com.myapplicati I/clp: a thread =180


上面的写法,那个占用了锁,就会执行完,然后再释放给其他线程使用。

private static Object object = new Object();

public static String getName() {
Log.i("clp", "getName thread=" + Thread.currentThread().getId());
synchronized (object) {//因为getFullName中的方法直接调用getName,是在同一个线程,所以可以直接使用
Log.i("clp", "a thread =" + Thread.currentThread().getId());
return "a";
}
}

public static String getFullName() {
Log.i("clp", "getFullName thread =" + Thread.currentThread().getId());
synchronized (object) {
Log.i("clp", "b thread =" + Thread.currentThread().getId());
return "b" + getName();//调用同样需要同步锁的getName方法
}
}


for (int j = 0; j < 5; j++) {
final int index = j;
new Thread(new Runnable() {
@Override
public void run() {
CldSyncUtil.getFullName();
}
}).start();
}


05-08 17:18:55.095 4039-4056/old.pkg.com.myapplicati I/clp: getName thread=175
05-08 17:18:55.095 4039-4058/old.pkg.com.myapplicati I/clp: getName thread=177
05-08 17:18:55.095 4039-4056/old.pkg.com.myapplicati I/clp: a thread =175
05-08 17:18:55.096 4039-4058/old.pkg.com.myapplicati I/clp: a thread =177
05-08 17:18:55.097 4039-4054/old.pkg.com.myapplicati I/clp: getName thread=173
05-08 17:18:55.097 4039-4054/old.pkg.com.myapplicati I/clp: a thread =173
05-08 17:18:55.098 4039-4057/old.pkg.com.myapplicati I/clp: getFullName thread =176
05-08 17:18:55.098 4039-4057/old.pkg.com.myapplicati I/clp: b thread =176
05-08 17:18:55.098 4039-4057/old.pkg.com.myapplicati I/clp: getName thread=176
05-08 17:18:55.098 4039-4057/old.pkg.com.myapplicati I/clp: a thread =176
05-08 17:18:55.098 4039-4055/old.pkg.com.myapplicati I/clp: getFullName thread =174
05-08 17:18:55.098 4039-4055/old.pkg.com.myapplicati I/clp: b thread =174
05-08 17:18:55.098 4039-4055/old.pkg.com.myapplicati I/clp: getName thread=174
05-08 17:18:55.098 4039-4055/old.pkg.com.myapplicati I/clp: a thread =174


上面的两种方式,都是线程外,会快速执行完毕。 但是线程内部,要等待其中一个线程(持有锁),执行完毕之后,释放锁,另外一个线程再获得锁,去执行。

68.executor和task优先于线程

使用线程池。

工程用会大量使用到线程的地方,最好封装一个工具类,统一来调度。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: