Java多线程-如何解决线程安全问题

方式一:同步代码块
* 关键字 * synchronized(同步监视器) * { * //需要被同步的代码 * } * 1.说明:操作共享数据的代码即为需被同步的代码 * 2.共享数据:多个线程共同操作的变量 * 3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。//Object obj=new Object(); * 要求:多个线程必须要共用同一把锁

方式二:同步方法
* 如果操作共享数据的代码完整声明在一个方法中,我们不妨将此方法声明为同步的。
* synchronized关键字
* public synchronized void show()
* 同步方法依然涉及同步监视器,只是不需要显示声明
* 非静态的同步方法,同步监视器是this
* 静态的同步方法,同步监视器是当前类本身
方式三:Lock锁

* 1.实例化ReentrantLock
* private ReentrantLock lock=new ReentrantLock();
* 2.调用锁定方法
*   lock.lock()
* 3.调用解锁方法
*   lock.unlock()
/**
 * 例子:创建三个窗口卖票,总票数100张,使用实现Runable接口的方式
 *存在线程安全问题,待解决
 *
 * 1.问题:卖票过程中,出现了重票、错票->线程安全问题
 * 2.原因:当某个线程操作车票的过程中,尚未完成操作时,其他线程也参与进来操作车票
 * 共享数据(共享信号量):车票数ticket
 * 3.解决:锁;
 * 4.在java中,通过同步机制来解决线程的安全问题
 *
 * 方式一:同步代码块
 * 关键字
 * synchronized(同步监视器)
 * {
 *     //需要被同步的代码
 * }
 * 1.说明:操作共享数据的代码即为需被同步的代码
 * 2.共享数据:多个线程共同操作的变量
 * 3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。//Object obj=new Object();
 * 要求:多个线程必须要共用同一把锁
 *
 *
 *
 * 方法二:同步方法
 * 如果操作共享数据的代码完整声明在一个方法中,我们不妨将此方法声明为同步的。
 * synchronized关键字
 * public synchronized void show()
 * 同步方法依然涉及同步监视器,只是不需要显示声明
 * 非静态的同步方法,同步监视器是this
 * 静态的同步方法,同步监视器是当前类本身
 *
 *
 * 5.同步的方式,解决了线程的安全问题。---好处
 *   操作同步代码时只能有一个线程参与,其他线程等待,相当于是一个单线程的过程,效率低----局限性
 *   死锁问题
 * 6.同步监视器是否唯一
 *
 * @author orz
 */


class Window1 implements Runnable
{
    private int ticket=100;
    //同步监视器
    Object obj=new Object();
    @Override
    public void run() {
        while (true)
        {
            //同步代码块方法实现数据共享
            synchronized (obj)
            {
                if(ticket>0)
                {
                    try
                    {
                        Thread.sleep(100);
                    }
                    catch(Exception e)
                    {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+ticket);
                    ticket--;
                }
                else
                {
                    break;
                }
            }
        }
    }
}


public class WindowTest {
    public static void main(String[] args) {

        Window1 w=new Window1();
        Thread t1=new Thread(w);
        Thread t2=new Thread(w);
        Thread t3=new Thread(w);


        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");

        t1.start();
        t2.start();
        t3.start();
    }
}

 

/**
 * 线程同步
 *
 *多线程共享变量
 *
 * 例子:创建三个窗口卖票,总票数100张,使用继承Thread类的方式
 *存在线程安全问题,待解决
 * 使用同步代码块方法解决线程安全问题
 *
 *
 * @author orz
 */
class Window2 extends Thread
{
    //类变量,共用同一个变量
    private static int ticket=100;

    //
    private  static Object obj=new Object();
    @Override
    public void run() {
        while (true)
        {
            synchronized (obj)
            {
                if(ticket>0)
                {
                    System.out.println(getName()+":卖票,票号为:"+ticket);
                    ticket--;
                }
                else
                {
                    break;
                }
            }

        }
    }
}
public class WindowTest2 {
    public static void main(String[] args) {
        Window2  w1=new Window2();
        Window2  w2=new Window2();
        Window2  w3=new Window2();


        w1.setName("窗口一");
        w2.setName("窗口二");
        w3.setName("窗口三");


        w1.start();
        w2.start();
        w3.start();

    }
}
/**
 * 使用同步方法来解决实现Runable接口的线程安全问题
 *
 * @author orz
 */
class Window3 implements Runnable
{
    private int ticket=100;
    public synchronized void show()
    {
        if(ticket>0)
        {
            try
            {
                Thread.sleep(10);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+ticket);
            ticket--;
        }

    }

    @Override
    public void run() {
       while (true)
       {
           show();
       }
    }
}


public class WindowTest3 {
    public static void main(String[] args) {

        Window3 w=new Window3();
        Thread t1=new Thread(w);
        Thread t2=new Thread(w);
        Thread t3=new Thread(w);


        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");

        t1.start();
        t2.start();
        t3.start();
    }
}
/**
 * 使用同步方法来解决继承Thread类的线程安全问题
 * @author orz
 */

class Window4 extends Thread
{
    //类变量,共用同一个变量
    private static int ticket=100;
    //同步监视器:WindowTest4.class
    //必须声明为静态方法
    public static synchronized void show()
    {
        if(ticket>0)
        {
            System.out.println(Thread.currentThread().getName()+":卖票,票号为:"+ticket);
            ticket--;
        }

    }
    @Override
    public void run() {
        while (true)
        {
            show();

        }
    }
}
public class WindowTest4 {
    public static void main(String[] args) {
        Window4  w1=new Window4();
        Window4  w2=new Window4();
        Window4  w3=new Window4();


        w1.setName("窗口一");
        w2.setName("窗口二");
        w3.setName("窗口三");


        w1.start();
        w2.start();
        w3.start();

    }
}
import java.util.concurrent.locks.ReentrantLock;

/**
 * 解决线程安全问题的方式三:Lock锁
 *
 * 1.实例化ReentrantLock
 *     private ReentrantLock lock=new ReentrantLock();
 * 2.调用锁定方法
 * lock.lock()
 * 3.调用解锁方法
 * lock.unlock();
 *
 *
 *
 * 面试题:synchronized与lock异同
 * 相同:
 * 不同:
 * synchronized机制执行完相应的同步代码之后,自动释放同步监视器
 * Lock需要手动的启动同步(lock()),结束同步也需要手动实现(unlock())
 *
 *
 * Lock、同步代码块、同步方法
 * @author orz
 */

class Window5 implements Runnable{
    private int ticket=100;
    /**
     * 1.实例化ReentrantLock
     */
    private ReentrantLock lock=new ReentrantLock();
    @Override
    public void run() {
        while (true)
        {
            //2.调用锁定方法
            try{lock.lock();
                if (ticket>0)
                {
                    try
                    {
                        Thread.sleep(100);
                    }
                    catch (Exception e)
                    {
                        e.printStackTrace();

                    }
                    System.out.println(Thread.currentThread().getName()+":售票,票号为:"+ticket);
                    ticket--;
                }
                else
                {
                    break;
                }
            }
            //3.调用解锁方法
            finally {
                lock.unlock();
            }

        }
    }
}

public class LockTest {
    public static void main(String[] args) {
        Window5 w=new Window5();
        Thread t1=new Thread(w);
        Thread t2=new Thread(w);
        Thread t3=new Thread(w);

        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");


        t1.start();
        t2.start();
        t3.start();

    }
}
posted @ 2020-07-27 22:11  orz江小鱼  阅读(420)  评论(0编辑  收藏  举报