//当个线程访问同一个资源的时候,要注意线程同步的问题,如果不同步容易造成数据没及时修改,然后就被另一个线程访问,得到的数据还是上一次的数据,造成数据错误的情况,以下demo可以很容易发现,为了便于发现我在上面休眠100毫秒,如果将ticket设为方法内的局部变量则就不会共享了。
package study0915;
public class ThreadTest implements Runnable{
private int ticket = 5;//卖票
/**
* 情景模拟:假设四个线程去执行卖票的功能,其中票为共享数据
*/
@Override
public void run() {
for (int i = 0; i < 20; i++) {
if(ticket>0){
try {
Thread.sleep(1000);
ticket--;
System.out.println(Thread.currentThread().getName() +"剩余票数" + ticket);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ThreadTest th = new ThreadTest();
new Thread(th,"A线程对象").start();
new Thread(th,"B线程对象").start();
new Thread(th,"C线程对象").start();
new Thread(th,"D线程对象").start();
}
D线程对象剩余票数1
B线程对象剩余票数1
A线程对象剩余票数1
C线程对象剩余票数1
D线程对象剩余票数0
C线程对象剩余票数-3
A线程对象剩余票数-2
B线程对象剩余票数-1
原因:
当多个线程访问统一资源,当A线程进入访问,休眠,其它线程也进来了,也休眠,但当都自醒后,可能线程1k快点,已经做了--的操作,但是取得的当前线程只有一个,所以不知道前面几个线程做了--的操作,这也就是数值不是按照43210-1-2-3这样排过来而是无序输出,这也是异步高效但是数据不同步的原因。
}
解决办法
//1.加入同步代码块
synchronized (this) {
if(ticket>0){
try {
Thread.sleep(1000);
ticket--;
System.out.println(Thread.currentThread().getName() +"剩余票数" + ticket);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//2.同步方法 上锁 单独将方法抽出来
public static synchronized void test(){
if(ticket>0){
try {
Thread.sleep(1000);
ticket--;
System.out.println(Thread.currentThread().getName() +"剩余票数" + ticket);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}