线程安全问题
经典的买票案例:
public class TicketNum implements Runnable {
int tickNum=100;
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
if(tickNum>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"还有"+(tickNum--)+"张票");
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
TicketNum tn=new TicketNum();
Thread t1=new Thread(tn,"窗口一");
Thread t2=new Thread(tn,"窗口二");
Thread t3=new Thread(tn,"窗口三");
t1.start();
t2.start();
t3.start();
}
}
结果
这就是线程安全问题,产生原因:
A:是否是多线程环境
B:是否有共享数据
C:是否有多条语句操作共享数据
解决
第一种:同步
public class TicketNum implements Runnable {
int tickNum=100;
@Override
//方法上加synchronized
public synchronized void run() {
// TODO Auto-generated method stub
while(true){
if(tickNum>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"还有"+(tickNum--)+"张票");
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
TicketNum tn=new TicketNum();
Thread t1=new Thread(tn,"窗口一");
Thread t2=new Thread(tn,"窗口二");
Thread t3=new Thread(tn,"窗口三");
t1.start();
t2.start();
t3.start();
}
}
结果:
第二种:加锁lock
public class TicketNum2 implements Runnable {
int tickNum = 100;
private static Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
lock.lock();// 锁定
if (tickNum > 0) {
try {
Thread.sleep(100); System.out.println(Thread.currentThread().getName() + "上锁"); System.out.println(Thread.currentThread().getName() + "还有" + (tickNum--) + "张票");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally { System.out.println(Thread.currentThread().getName() + "解锁");
lock.unlock();// 解锁
}
}
}
}
}
public class LockDemo {
public static void main(String[] args) {
TicketNum2 tn=new TicketNum2();
Thread t1=new Thread(tn,"窗口一");
Thread t2=new Thread(tn,"窗口二");
Thread t3=new Thread(tn,"窗口三");
t1.start();
t2.start();
t3.start();
}
}
结果:
sleep()与wait()
对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。
在调用sleep()方法的过程中,线程不会释放对象锁。
而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备
获取对象锁进入运行状态。
扫描二维码关注公众号,回复:
187813 查看本文章
创建线程的方式
1.继承Thread类,不推荐
2.实现Runnable 接口
3.实现java.util.concurrent下的Callable接口