Java----线程的同步

Java----线程的同步

引入问题

在关于线程的操作时,往往会遇到线程的安全问题。
这里我用一个例子来说明:

package com.CharlesLC_Test;

public class Window_Test {
    public static void main(String[] args) {
        Window window = new Window();
        Thread window1 = new Thread(window);
        Thread window2 = new Thread(window);
        Thread window3 = new Thread(window);
        window1.setName("窗口一");
        window2.setName("窗口二");
        window3.setName("窗口三");
        window1.start();
        window2.start();
        window3.start();

    }

}
class Window implements Runnable{
    private int tickets = 100;
    @Override
    public void run() {
        while(true) {
            if (tickets > 0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":成功取票"+tickets+"还剩下" + --tickets);
            }
            else{break;}
        }
    }
}

结果:发现窗口出现了重票
在这里插入图片描述
问题所在:
对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。

线程同步的方式

使用Synchronized.

当一个线程调用对象的一段synchronized代码时,需要先获取这个锁,然后去执行相应的代码,执行结束之后,释放锁。当一个线程拿到这个锁时,其他线程不能进入被这个锁起来的这段代码。

同步代码块

使用方法:
synchronized(对象){//需要被同步的代码;}
这里我修改了取票这个例子中的Window类:

class Window implements Runnable{
    private int tickets = 100;
    @Override
    public void run() {
        while(true) {
        // 这里作了改变,把这段代码用 synchronized锁了起来
            synchronized (this) {
                if (tickets > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":成功取票" + tickets + "还剩下" + --tickets);
                } else {
                    break;
                }
            }
        }
    }
}

结果:
在这里插入图片描述

同步方法:

使用方法:
public synchronized void show(String name){ }

修改过的Window类

class Window implements Runnable{
    private int tickets = 100;
    @Override
    public void run() {
        while(true) {
            show();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (tickets == 0){
                break;
            }
        }
    }

    private synchronized void show() {
        if (tickets > 0) {
            System.out.println(Thread.currentThread().getName() + ":成功取票" + tickets + "还剩下" + --tickets);
        }

    }
}

结果:
在这里插入图片描述

  • 当前线程的同步方法、同步代码块执行结束。
  • 当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。
  • 当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束。
  • 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。
    注意:必须确保使用同一个资源的多个线程共用一把锁,这个非常重要,否则就无法保证共享资源的安全

使用Lock()

导入
import java.util.concurrent.locks.ReentrantLock;

使用方式:

class A{
        private final ReentrantLock lock=new ReenTrantLock();
       public void m(){
        lock.lock()
        try{
        //保证线程安全的代码;
        finally{
        lock.unlock();
}

synchronized与Lock的对比

1.Lock是显式锁(手动开启和关闭锁,别忘记关闭锁),synchronized是隐式锁,出了作用域自动释放
2.Lock只有代码块锁,synchronized有代码块锁和方法锁
3.使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类)

发布了10 篇原创文章 · 获赞 8 · 访问量 1408

猜你喜欢

转载自blog.csdn.net/weixin_45640609/article/details/104553708