为什么要学习线程,因为我们可以把复杂、异步的代码转化为更简单、更直观的代码,从而简化复杂系统的开发。
线程的发展
多进程/多线程发展优势
- 资源利用
当程序需要等待输入输出的时候。等待时候可以让系统做一些有意义的其他事情,提供效率。 - 公平
多个用户或多个程序拥有平等的优先级,他们可以通过时间片方式来共享计算机。这把串行方式一个程序结束后,另外一个程序开始更加公平。 - 方便
编写一个单独执行的任务并进行必要的相互协调比编写一个程序来执行多个任务的逻辑更加容易,且更容易让人接受。
线程的风险
返回序列的方法
public class UnsafeSequence {
private int value;
//返回一个唯一的数值
public int getNext(){
return value++;
}
}
封装线程
public class UnsafeSequenceRunnable implements Runnable {
private UnsafeSequence sequence;
public UnsafeSequenceRunnable(UnsafeSequence sequence) {
this.sequence = sequence;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
System.out.println(String.format("当前线程:%s,数字为:%s", Thread.currentThread().getName(), sequence.getNext()));
}
}
}
测试结果发现。值少1
/**
* 测试结果
*
* 当前线程:pool-1-thread-4,数字为:99996
* 当前线程:pool-1-thread-4,数字为:99997
* 当前线程:pool-1-thread-4,数字为:99998
*/
public class UnsafeSequenceTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
UnsafeSequence sequence = new UnsafeSequence();
for (int i = 0; i < 10; i++) {
executorService.execute(new UnsafeSequenceRunnable(sequence));
}
executorService.shutdown();
}
}
三个步骤,有可能被抵消了
优化改造,关键方法加锁
public class SafeSequence {
private int value;
//返回一个唯一的数值
public synchronized int getNext(){
return value++;
}
}
其他
多线程的风险
- 死锁
- 上下文切换的代价
对于多个线程访问同一个变量,可解决问题的办法
- 不要跨线程共享变量
- 使用状态变量为不可修改
- 在任何情况下访问状态变量的时候使用同步