java多线程详解(三)-----线程的同步

今天参照大牛的博客,自己写了一下多线程实现窗口卖票的程序,很久没写多线程了,记得第一家公司就是做的这个,今天记录一下,重写一下。

利用多线程模拟 3 个窗口卖票

继承 Thread 类

package Thread;

public class SellThread extends Thread {
        //定义一共有 50 张票,注意声明为 static,表示几个窗口共享
    private static int num = 50;

    //调用父类构造方法,给线程命名
    public SellThread(String string) {
        super(string);
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            synchronized (this.getClass()) {
                if (num > 0) {
                    try {
                        sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(this.currentThread().getName() + "卖出一张票,剩余" + (--num) + "张");
                }
            }
        }
    }
}

实现runnable接口:

package Thread;

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

public class SellRunnable implements Runnable {
    //定义一共有 50 张票,继承机制开启线程,资源是共享的,所以不用加 static
    private int num = 50;
    //    @Override
//    public void run() {
//        //票分 50 次卖完
//        for(int i = 0 ; i < 50 ;i ++){
//            sell();
//        }
//    }
//
//    private synchronized void sell(){
//        if(num > 0){
//            try {
//                //模拟卖一次票所需时间
//                Thread.sleep(10);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName()+"卖出一张票,剩余"+(--num)+"张");
//        }
//    }
    //创建一个锁对象
    Lock l = new ReentrantLock();

    @Override
    public void run() {
        //票分 50 次卖完
        for (int i = 0; i < 50; i++) {
            //获取锁
            l.lock();
            try {
                if (num > 0) {
                    //模拟卖一次票所需时间
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + "卖出一张票,剩余" + (--num) + "张");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //释放锁
                l.unlock();
            }
        }
    }
}

main函数

package Thread;

public class Main {
    public static void main(String[] args) {
//        SellThread sellThread1 = new SellThread("A窗口");
//        SellThread sellThread2 = new SellThread("B窗口");
//        SellThread sellThread3 = new SellThread("C窗口");
//        sellThread1.start();
//        sellThread2.start();
//        sellThread3.start();
        SellRunnable r = new SellRunnable();
        Thread t1 = new Thread(r,"A窗口");
        Thread t2 = new Thread(r,"B窗口");
        Thread t3 = new Thread(r,"C窗口");
        t1.start();
        t2.start();
        t3.start();
    }
}

这里用了三种方法做线程同步:
1,使用同步代码块
2,使用同步方法
3,使用锁机制

为什么要使用线程同步,如果不使用线程同步,可能两个线程会同时进入代码块,导致窗口间卖了同一张票,不能使票保持独占。
java多线程详解(三)-----线程的同步
其中第一个继承thread线程的方式用了同步代码块,第二种实现runnable接口用了同步方法和锁机制,当然实现runnable接口也可以使用同步代码块。但是继承thread使用同步方法和锁机制时会出现问题,因为new了三个对象,他们的三个对象的sell方法和lock对象不同,到最后会出现负票情况。

参考地址:https://www.cnblogs.com/ysocean/p/6883729.html