首先为什么会引发线程安全问题:
多线程共享数据时存在线程的安全问题(线程间没有共享数据是不会发生线程安全问题) 这边我们举个例子来说明
第一个 :窗口卖票问题 我们现在有三个窗口要卖100张票 代码如下:
class Window1 implements Runnable{
private int ticket=100;
@Override
public void run() {
while(true){
if(ticket>0){
System.out.println(Thread.currentThread().getName()+":"+ticket);
ticket--;
}
else {
break;
}
}
}
}
public class TicketingThread1 {
public static void main(String[] args){
Window1 window1=new Window1();
Thread w11=new Thread(window1);
Thread w12=new Thread(window1);
Thread w13=new Thread(window1);
w11.setName("窗口一");
w12.setName("窗口二");
w13.setName("窗口三");
w11.start();
w12.start();
w13.start();
}
}
它的执行结果为:
出现了重票问题
为什么这个会出现重票问题呢
是因为我们有三个线程要操作这100张票 当线程一在执行run的时候当它还没执行完线程二或线程三就进去执行run操作ticket (ticket属于这三个线程的共享数据)。如图之所以会出现3个100的原因是因为当线程三进去取100的时候但是还没有操作完线程二和线程一就进去取100的票导致最终出现三张100,当然其他号数的票也是这样。
如何解决呢
在Java中我们使用同步机制来解决线程的安全问题,
方法一:使用同步代码块
也就是加锁:当有线程在执行共享数据的时候 将这部分代码锁上 其他线程不能进来执行 必须等该线程执行结束后才能给其他线程执行
synchronized(同步监视器){ * //需要被同步的代码 * } * 说明:1.操作共享数据的代码,即为需要被同步的代码 * 2.共享数据:多个线程共同操作的变量。比如ticket就是共享数据 * 3.同步监视器,俗称锁,任何一个对象都可以充当锁 * 要求:多个线程必须使用同一个锁
代码如下:
class Window1 implements Runnable{
private int ticket=100;
Object object=new Object();
@Override
public void run() {
while(true){
synchronized(object){
if(ticket>0){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+ticket);
ticket--;
}
else {
break;
}
}
}
}
}
public class TicketingThread1 {
public static void main(String[] args){
Window1 window1=new Window1();
Thread w11=new Thread(window1);
Thread w12=new Thread(window1);
Thread w13=new Thread(window1);
w11.setName("窗口一");
w12.setName("窗口二");
w13.setName("窗口三");
w11.start();
w12.start();
w13.start();
}
}
执行结果如下:
解决了重票的线程安全问题 但是该过程相当于变成了单线程使得运行速度变慢。
方法二:使用同步方法
将共享数据的代码写在同一个方法里面 然后线程中调用该方法
* 1.同步方法仍涉及到同步监视器,只是不需要我们显示的声明 * 2.非静态的同步方法,同步监视器是this * 静态的同步方法,同步监视器是当前类本身
代码如下:
class Window2 implements Runnable{
private int ticket=100;
@Override
public void run() {
while(true){
show();
if(ticket<=0){
break;
}
}
}
private synchronized void show(){//同步监视器是this
if(ticket>0){
System.out.println(Thread.currentThread().getName()+":"+ticket);
ticket--;
}
}
}
public class TicketingThread2 {
public static void main(String[] args){
Window2 window2=new Window2();
Thread t1=new Thread(window2);
Thread t2=new Thread(window2);
Thread t3=new Thread(window2);
t1.setName("窗口一");
t2.setName("窗口二");
t3.setName("窗口三");
t1.start();
t2.start();
t3.start();
}
}
以上就是线程的安全问题以及解决方法 与君共勉