同步的问题

看一段代码

class MyThread implements Runnable{
    private int ticket=5;
    @Override
    public void run() {
        while (true){
            if (this.ticket>0){
                try {
                    Thread.sleep(100);//模拟延迟操作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                this.ticket--;
                System.out.println(Thread.currentThread().getName()+"卖票:"+this.ticket);
            }else{
                System.out.println("票卖光了");
                break;
            }
        }
    }
}

public class Main{
    public static void main(String[] args) {
        MyThread mt=new MyThread();
        new Thread(mt,"票贩子A").start();
        new Thread(mt,"票贩子B").start();
        new Thread(mt,"票贩子C").start();
    }
}

以上代码很可能会出现负数,或者卖出不止5次票

这个问题需要用同步进行等待,如果想要在程序中实现同步功能可以使用synchronized关键字来实现

在同步代码块的操作里面的代码只允许一个线程执行

class MyThread implements Runnable{
    private int ticket=5;
    @Override
    public void run() {
        while (true){
            synchronized (this){//在这个代码块中表示每一次只能允许一个线程进行访问
                if (this.ticket>0){
                    try {
                        Thread.sleep(100);//模拟延迟操作
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    this.ticket--;
                    System.out.println(Thread.currentThread().getName()+"卖票:"+this.ticket);
                }else{
                    System.out.println("票卖光了");
                    break;
                }
            }
        }
    }
}

public class Main{
    public static void main(String[] args) {
        MyThread mt=new MyThread();
        new Thread(mt,"票贩子A").start();
        new Thread(mt,"票贩子B").start();
        new Thread(mt,"票贩子C").start();
    }
}

加入同步处理之后,程序的整体性能下降了,同步实际上会造成性能的降低

也可以在如下方法使用

把sysnchronized放在方法前面

class MyThread implements Runnable {
    private int ticket = 10;

    public synchronized void sale() {
        while (true) {
            //在这个代码块中表示每一次只能允许一个线程进行访问
            if (this.ticket > 0) {
                try {
                    Thread.sleep(100);//模拟延迟操作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                this.ticket--;
                System.out.println(Thread.currentThread().getName() + "卖票:" + this.ticket);
            } else {
                System.out.println("票卖光了");
                break;
            }

        }
    }

    @Override
    public void run() {
        this.sale();
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        new Thread(mt, "票贩子A").start();//必须是同一个对象
        new Thread(mt, "票贩子B").start();
        new Thread(mt, "票贩子C").start();
    }
}

系统中许多类上使用的同步处理采用的都是同步方法

死锁

死锁是在进行多线程同步的处理之中有可能产生的一个问题,所谓死锁指的是若干个线程,彼此互相等待的概念,过多的同步操作会造成死锁。

以下代码可能会造成死锁的情况

class A{
    public synchronized void say(B b){
        System.out.println("a先生说:把你的本给我,我给你笔,否则不给");
        b.get();
    }
    public synchronized void get(){
        System.out.println("A先生得到本,付出了笔");
    }
}
class B{
    public synchronized void say(A a){
        System.out.println("b:先生说:把你的笔给我");
        a.get();
    }
    public synchronized void get(){
        System.out.println("B先生得到了笔,付出了本");
    }
}

public class Main implements Runnable{
    private static A a=new A();
    private static B b=new B();
    public static void main(String[]args)throws Exception{
        new Main();
    }
    public Main(){
        new Thread(this).start();
        b.say(a);
    }

    @Override
    public void run() {
        a.say(b);
    }
}

执行结果可能是

b:先生说:把你的笔给我
a先生说:把你的本给我,我给你笔,否则不给

由于俩个类都使用了同步方法定义,就会造成a对象等待b对象执行完毕,而b对象等待a对象执行完毕,这样就会造成死锁的现象

根本原因是synchronized锁方法的时候是给当前对象加锁,想要执行必须获得当前对象的锁,但俩个方法都互相持有对方想要获取的对象的锁,都拿在手里,去获取对方手里的锁,所以很有可能会造成死锁

Last modification:April 21, 2022
如果觉得我的文章对你有用,请随意赞赏