多线程并发,给变成带来很多好处,可以完成更多有效率的程序,但是也会带来线程安全的问题。
举例。3个售票窗口同时售卖2000张票;
/*演示使用线程的注意事项
*
*
*
* */
package tank2;
public class test {
public static void main(String[] args) {
// TODO Auto-generated method stub
//定义3个售票窗口
TicketWindow tw1 = new TicketWindow();
//TicketWindow tw2 = new TicketWindow();
//TicketWindow tw3 = new TicketWindow();
Thread t1 = new Thread(tw1);
Thread t2 = new Thread(tw1);
Thread t3 = new Thread(tw1);
t1.start();
t2.start();
t3.start();
}
}
//售票窗口类
class TicketWindow implements Runnable{
private int nums =2000;
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
//if else 语句需要保持原子性(同步代码块)
//synchronized (this) {
//先判断是否还有票
if (nums >0) {
//一秒出一张
try {
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
}
//Thread.currentThread().getName()
//当前线程的名字
System.out.println(Thread.currentThread().getName()+"正在售出第" + nums +"张票");
nums--;
} else {
//售票结束
break;
}
//}
}
}
}
执行结果:
Thread-0正在售出第2000张票
Thread-1正在售出第2000张票
Thread-2正在售出第1998张票
Thread-1正在售出第1997张票
Thread-0正在售出第1997张票
Thread-2正在售出第1995张票
Thread-0正在售出第1994张票
Thread-1正在售出第1994张票
碰到这种情况:同一张票被多个售票窗口出售,惹祸的代码就是:
if (nums >0) {
//一秒出一张
try {
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
}
//Thread.currentThread().getName()
//当前线程的名字
1.System.out.println(Thread.currentThread().getName()+"正在售出第" + nums +"张票");
2.nums--;
当a线程在执行1语句时,正要执行2语句时,b线程开始执行这时候num还没有被减1,导致同一张票出现多次售卖的情况。
解决这个问题的关键性就是要保证容易出问题的代码的原子性:所谓的原子性就是指当a线程在执行某段代码的时候,别的线程必须要等到a线程执行完后,别的线程才能开始执行这段代码。类似将对象上锁 ,需要释放锁后才能被别的线程引用。
通过synchronized (object) {容易出问题的代码}来实现
/*演示使用线程的注意事项
*
*
*
* */
package tank2;
public class test {
public static void main(String[] args) {
// TODO Auto-generated method stub
//定义3个售票窗口
TicketWindow tw1 = new TicketWindow();
//TicketWindow tw2 = new TicketWindow();
//TicketWindow tw3 = new TicketWindow();
Thread t1 = new Thread(tw1);
Thread t2 = new Thread(tw1);
Thread t3 = new Thread(tw1);
t1.start();
t2.start();
t3.start();
}
}
//售票窗口类
class TicketWindow implements Runnable{
private int nums =2000;
@Override
public void run() {
// TODO Auto-generated method stub
while(true) {
//if else 语句需要保持原子性(同步代码块)
synchronized (this) {
//先判断是否还有票
if (nums >0) {
//一秒出一张
try {
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
}
//Thread.currentThread().getName()
//当前线程的名字
System.out.println(Thread.currentThread().getName()+"正在售出第" + nums +"张票");
nums--;
} else {
//售票结束
break;
}
}
}
}
}
这样就能保证线程之间数据的安全。