线程的安全问题

线程安全问题:java

问题:当某个线程操做共享数据中,还没有操做完成时,其余线程参与进来,也操做共享数据。安全

解决方法:当一个线程在操做共享数据时,其余线程不能参与进来。即便操做中的线程出现阻塞,也不能改变。多线程

例子:建立三个窗口卖票,总票数为100张,使用实现Runable接口的方式。ide

JAVA 中经过同步机制 来解决线程的安全问题。this

方式1、同步代码块

 synchronized(同步监视器){spa

    //须要被同步的代码   线程

code

说明:对象

1.操做共享数据的代码,为须要被同步的代码继承

2.共享数据,多个线程共同操做的变量,

3.同步监视器,俗称:锁。任何一个类的对象,均可以充当锁。

    要求:多个线程必需要共用同一把锁。

 补充:在实现Runable接口建立多线程的方式中,咱们能够考虑使用this 充当同步监视器

使用实现 Runable方式:

public class TheardWindow {
    public static void main(String[] args) {
        TicketWindow w1 = new TicketWindow();
        Thread t1=new Thread(w1);
        Thread t2= new Thread(w1);
        Thread t3 =new Thread(w1);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();;
        t2.start();
        t3.start();

    }
}
class TicketWindow implements Runnable{
    private  int ticket=100;
    final Object obj=new Object();

    @Override
    public void run() {
        while (true){
            //synchronized (obj){
            synchronized (this){
                if (ticket>0){
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":卖票 票号:"+ticket);
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }
}

使用继承方式: 

package org.zhanghl;

public class WindowB {
    public static void main(String[] args) {
        TicketRun t1= new TicketRun();
        TicketRun t2= new TicketRun();
        TicketRun t3 =new TicketRun();
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

class TicketRun extends Thread{
    private static int ticket=100;
    private static Object obj=new Object();
    @Override
    public void run() {
        while (true){
            //synchronized (obj){
            //能够用当前类作锁
            synchronized (WindowB.class){
                if (ticket>0){
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":卖票 票号:"+ticket);
                    ticket--;
                }else {
                    break;
                }
            }
        }
    }
}

 

使用同步代码块 解决继承Thread类的方式的线程安全问题

注意:

1. 共享数据与锁对象都应是惟一的,这里为static.

2. 用继承Thread类建立多线程的方式时,慎用this充当同步监视器,考虑使用当前类对象作锁。Class只会加载一次。

3. 同步的方式,优势是解决了线程的安全问题,

    缺点是操做同步代码时,只能由一个线程参与,其余线程等待。先当与是一个线程的过程,效率低。

 

方式2、同步方法

若是操做共享数据的代码完整的声明在一个方法中。咱们不妨将此方法声明同步的

package org.zhanghl;

/*
 * 使用同步方法解决实现Runable接口的线程安全问题
 * */

class WindowC1 implements Runnable {
    private int ticket = 100;
    final Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            if (ticket > 0) {
                show();
            } else {
                break;
            }
        }
    }

    /*同步监视器:this */
    private synchronized void show() {
        if (ticket > 0) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":卖票 票号:" + ticket);
            ticket--;
        }
    }
}
/*
*使用同步方法处理继承Thread类的方式中的线程安全问题
* */
class WindowC2 extends Thread{
    private static int ticket = 100;
    final Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            if (ticket > 0) {
                show();
            } else {
                break;
            }
        }
    }

    /*同步监视器:this */
    private static synchronized void show() { /*此时同步监视器是 WindowC2.class*/
        //private synchronized void show() 此种方式是错误的
        if (ticket > 0) {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":卖票 票号:" + ticket);
            ticket--;
        }
    }
}
public class WindowC {
    public static void impl_show(){
        WindowC1 w1 = new WindowC1();
        Thread t1 = new Thread(w1);
        Thread t2 = new Thread(w1);
        Thread t3 = new Thread(w1);
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }

    public static  void extd_show(){
        WindowC2 t1=new WindowC2();
        WindowC2 t2=new WindowC2();
        WindowC2 t3=new WindowC2();
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
    public static void main(String[] args) {
        /*实现方式,同步方法*/
       //impl_show();
        /*继承方式,同步方法*/
        extd_show();
    }
}

 

总结:

1.同步方法仍然涉及到同步监视器,只是不须要咱们显示的声明。

2.非静态的同步方法,同步监视器是this.

静态的同步方法,同步监视器是 当前类自己。

相关文章
相关标签/搜索