多线程安全问题
这个在我印象中,比较经典就是两个人同时对同一张银行卡进行操作,注意是同时操作,那么会出现什么问题呢。
原本银行卡里面有1000万,一个人张三在取钱100万同时一个人李四存钱200万,那么按照我们正常人的思维就是1000-100+200=1100万。
但是两人一开始在不同柜台对同一张银行卡读取卡里面的余额的时候,张三看到是1000万,李四看到也是1000万,张三取完钱,再读取余额事就变成了900万(因为张三取了100万)。李四存了200万,再查询就是1200万。那么是不是就会出现余额不准确的问题,到底是900万还是1200万。
解决方法
常用方法就是加锁(同步)。什么意思,就是多个线程同时对一个共享资源进行修改的时候,先获取资源的人(获取锁)的那么就会独占资源(加锁),其他线程只有等待(阻塞)当前线程修改完毕后再进行操作。
注意:不要对所有资源(代码)进行加锁,这样的话,那么独占资源的线程就可以慢悠悠的运行,其他线程就只能等着。
方法一:同步代码块
写法如下,这个单词有点难写哈。
synchronized (obj) { // obj是指锁对象(需要唯一)
//方法体里面就是线程独占执行的代码
}
方法二:同步方法
在返回值前面加上synchronized,表示当前方法只有运行中状态的线程独占。
常见的案例有:Hashtable、Vector、StringBuffer。这些在java中都不推荐使用,虽然都比较安全,但是性能就比较低下,我们就是常用hashmap,StringBuilder.
public synchronized void func(){
}
死锁问题
这个就是对多处位置加了synchronized,一个线程占了一个锁,另外一个线程占了另外一个锁,然后执行到下一步时,就会一直等待对方退出,然后就是这样,就像交通堵塞一样。
线程通信(等待以及唤醒)
1.obj.wait();当前线程就是从运行中状态退出,进入等待状态,要被唤醒obj.notify();才能到执行状态,去抢时间片。
- obj.wait(time); 等待被唤醒或者时间结束自己醒来。
- obj.notify()方法是唤醒obj锁对象的wait等待。如果有多个,会随机唤醒其中一个。
- obj.notifyAll()是唤醒所有的obj对象等待的线程。
易错点:不论是wait方法还是notify方法,都必须在线程同步代码执行。
sleep()和wait()的区别
- Thread.sleep(毫秒数);只有等到时间结束,而obj.wait(毫秒数)是时间结束或者被唤醒就变成执行状态。
- Thread.sleep(毫秒数)在休眠懂得时候如果是持有锁就会带锁睡觉,其他线程无法抢占时间片,只有等待;而obj.wait(毫秒数);是退出运行中状态,也就是把锁释放了,其他线程可以强占时间片。
- sleep在调用时不需要持有锁(即Thread.sleep(毫秒数);也需要在synchronized里面),而wait必须要持有锁时才能调用。
线程中止
设计一个条件,比如说time == 50 就break,其实中止必须要用break语句来完成。
这个没有写清楚,以后待写。
多线程真的是很难。
线程池
池是用来存放对象的集合。作用就是管理多个对象,以达到对象的重用,减少new创建以及销毁的时间。因为Java十分耗费资源,这个就是天生的,你看写Java代码比写python多得多,但是Java多平台特点十分给力。
线程的作用
- 可以设置线程的数量上限。
- 可以重复使用线程,每次使用完毕后放入池中,方便下次使用。
- 减少创建以及销毁的时间。
写一个创建固定大小的线程池吧。
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
String name = Thread.currentThread().getName(); //主线程
for( int i = 0 ; i < 5 ; i++) {
System.out.println(name +"运行次数"+i);
}
}
};
ExecutorService service = Executors.newFixedThreadPool(4); //创建一个固定大小的,这里是只有4个的线程池
//下面是给线程池中4个线程,7个任务,那么最多4个线程同时运行,还有三个线程一开始需要等待
service.submit(runnable);
service.submit(runnable);
service.submit(runnable);
service.submit(runnable);
service.submit(runnable);
service.submit(runnable);
service.submit(runnable);
service.shutdown();
}
Lock接口以及常用的实现类
lock()接口和synchronized作用相同,就是加锁。
先写到这里吧,以后再写