线程的代码理解
简单来说,就是调用线程对象的start方法,当调用了该方法后,该线程就可以独立运行。调用start方法,其实运行的是线程内部的run方法,而run方法一般都是写的while循环(这样可以让线程一直运行,当不满足条件的时候自动退出)
为什么会出现线程安全问题
当线程运行的时候,他们运行状态是独立的,但是资源是共享的。
public class ThreadTest {
public static void main(String[] args) {
Runn runn=new Runn();
Thread thread1=new Thread(runn);
Thread thread2=new Thread(runn);
Thread thread3=new Thread(runn);
thread1.start();
thread2.start();
thread3.start();
}
}
class Runn implements Runnable{
private Integer num=10;
@Override
public void run() {
while (num>0){
try {
Thread.sleep(1000);
num--;
System.out.println("还剩下"+num+"张票");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
上面的num是线程共享的,当三个线程执行后,各自执行自己的run方法,访问的都是num,这样就可能出现:我在操作这个变量的时候,别的线程也在操作,最后我明明只减了1,但是结果却出现减了3,这就是三个线程同时进行了操作.还有我的判定条件是大于0,但是结果出现了小于0的情况
这个原因就是:当num=1的时候,被线程1,2,3同时进行访问,想要-1,然而真正进行-1的时候,得到的是其他线程已经操作过的num(线程执行有先后顺序),这个时候num的值是0,所以操作后,最后的值就小于0了。
解决线程安全
解决的思路就是当我在访问这个变量时,其他线程不应该进行操作,必须等我操作完成后,其他线程才能执行操作。
实现方法就是加锁
- 同步代码块sychronized(锁)
public void run() {
synchronized (this) {
while (num > 0) {
try {
Thread.sleep(1000);
num--;
System.out.println("还剩下" + num + "张票");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
实现原理就是:当执行这段代码时就必须获取锁,然而每个对象都只有一个锁,所以就可以保证每次都只有一次操作在执行
2.Lock
private Lock lock=new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock();
if (num > 0) {
try {
Thread.sleep(1000);
num--;
System.out.println(Thread.currentThread().getName() + ":" + "还剩下" + num + "张票");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.unlock();
}
}