synchronized站点抢票同步例题


多线程环境安全问题的判断标准(一定要三个同时满足)
是否是多线程环境
是否有共享数据

是否有多条语句操作(修改)共享数据

为什么出问题:
CPU的一次操作必须是原子性的,在一个时间点,CPU只能执行一条指令,而一条语句是由多条指令组成的,比如说i++指令,CPU要先执行i+1,然后将i+1的值赋给i,然后再输出。我们用一条语句来理解,比如下面的卖票程序,当A站点输出语句“A站点还剩88张票”,这个时候还没执行到i--语句,这是B站点抢占到CPU,因为i--还没有执行,B站点也会输出“B站点还剩88张票”,这就出现了线程安全问题。

线程方法:

public final int getPriority()  回去当前线程名
public final void setPriority(int newPriority)  设定当前线程名

public static void sleep(long millis) 线程休眠

public final void join() 线程加入  意思是加入的线程优先运行,运行结束后才会轮到下一个线程   注意:必须先开启该线程才能加入线程

public static void yield()  线程礼让 目的时尚线程抢占更加均衡

public final void setDaemon(boolean on)  后台线程:守护线程,精灵线程

public final void stop():中断线程  不建议使用
public void interrupt(): 中断线程

 如何正确地停止一个线程?

A:①、使用退出标志,使线程正常退出,也就是当 run 方法完成后线程终止;
②、使用 interrupt 方法中断线程
③、使用 stop 方法强行终止,但是不推荐使用,因为 stop 和 suspend 以及 resume 一样存在死锁威胁,并且都是过期作废的方法。

第一种,继承Thread创建多线程,同步方法,静态锁obj对象,使用同步代码块。  

两者不同点红色标注

public class MyThread extends Thread{
    static int i=100 ;
    static Object obj=new Object();
    
    public MyThread() {
        super();
    }
    public MyThread(String name) {    
        super(name);
    }

    @Override
    public void run() {
        while(i>0){
            synchronized (obj) {//obj对象必须静态,否则两个对象调用的obj不相同,必须保证只有一把锁
                System.out.println(Thread.currentThread().getName()+"抢到票,还剩"+i+"张票");
                i--;
            }
        }
    }
}

public class ThreadTest {
public static void main(String[] args) {
    MyThread thread1 = new MyThread("A站点");
    MyThread thread2 = new MyThread("B站点");
    thread1.start();
    thread2.start();
}
}
执行结果
B站点抢到票,还剩100张票
A站点抢到票,还剩99张票
A站点抢到票,还剩98张票
A站点抢到票,还剩97张票
A站点抢到票,还剩96张票
A站点抢到票,还剩95张票
A站点抢到票,还剩94张票
A站点抢到票,还剩93张票
A站点抢到票,还剩92张票
A站点抢到票,还剩91张票
A站点抢到票,还剩90张票
A站点抢到票,还剩89张票
A站点抢到票,还剩88张票
A站点抢到票,还剩87张票
A站点抢到票,还剩86张票
A站点抢到票,还剩85张票
A站点抢到票,还剩84张票
A站点抢到票,还剩83张票
A站点抢到票,还剩82张票

第二种 实现runnable接口

 1 public class MyRunnable implements Runnable {
 2     int i=100;
 3     Object obj =new Object();
 4     @Override
 5     public void run() {
 6         while(i>0) {
 7              //因为线程虽然有两个 但是多态得到的子类对象只有一个 所以不用静态obj 
 8             //在这里使用代码块而不使用同步关键字修饰方法是因为同步方法,那一个对象会把这个方法执行完才会跳出循环,那就没票了
 9             //使用obj和this是一个意思
10             synchronized(this) { 
11                 System.out.println(Thread.currentThread().getName()+"抢到票,还剩"+i+"张票");
12                 i--;
13                 try {
14                     Thread.sleep(100);//加个休眠模拟网络延迟,不知道为什么不加休眠一个线程能抢光所有的票
15                 } catch (InterruptedException e) {
16                     // TODO Auto-generated catch block
17                     e.printStackTrace();
18                 }
19             }
20         }
21     }
22 }
23 
24 public static void main(String[] args) {
25     MyRunnable runnable =new MyRunnable();
26     Thread thread1 = new Thread(runnable,"A站点");
27     Thread thread2 = new Thread(runnable,"B站点");
28     thread2.start();
29     thread1.start();
30 }
31 }
原文地址:https://www.cnblogs.com/19322li/p/10698815.html