35.线程安全

注意事项!

synchronized(几把特殊的锁){}

  • 字符串常量:""
  • Runnable中的对象:this
  • 字节码对象:MyRunnable.class

在当前线程下,如果有子线程正在执行,想等待子线程执行完了再继续执行,可以使用Thread下的join方法(子线程对象.join())

不同步,不安全,效率高(需要则用锁机制) 同步,安全,效率很低(很少使用)
ArrayList Vector
HashMap Hashtable(不允许null键值)
StringBuilder StringBuffer

使用锁的时候最好使用try...catch...finally{ lock.unlock(); }语句,这样可以最大限度避免死锁

try {} finally { lock.unlock(); }这种结构也是允许的!

包装类不适合当做锁,如果包装类的值发生改变,会自动装箱,这时可能会new一个新的对象,这个锁就毫无意义了

一、线程不安全

线程安全:如果有多个线程在同时运行,这些线程可能会同时运行这段带啊,如果每次运行结果是一样的,其他变量的值也和预期是一样的,那线程就是安全的

如果要保存线程安全地加一把锁!

线程安全问题

  • ①线程安全是由静态变量以及全局变量(公共变量)引起的;
  • ②多线程对公共变量进行读操作是线程安全的。
  • ③多线程对公共变量进行写操作,得考虑线程同步问题,否则线程就不安全。

二、线程同步

同步机制synchronized /'sɪŋ krə naɪ zd/
为了保证每个线程都能正常执行原子操作,java引入了线程同步机制

  • ①同步代码块。
  • ②同步方法。
  • ③锁机制。

三、同步代码块

  • 同步代码块synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
    适合相同逻辑代码(代码一样)进行同步。

格式

synchronized(同步锁){
    需要同步操作的代码
}

同步锁

  • 锁对象,可以是任意类型。
  • 多个线程对象 要使用同一把锁

注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他线程只有等待(BLOCKED)。

class Ticket implements Runnable{
    private int ticket = 10;
    
    // new 一个公共锁,谁拿到锁,谁就执行,执行完了,就释放锁。
    Object lock = new Object();
    public void run() {
        String threadName = Thread.currentThread().getName();

        while (ticket > 0){

            try {
                System.out.println("正在购票中,请稍后...");
                Thread.sleep(500L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 同步代码块
            synchronized(lock) {
                if(this.ticket > 0) {
                    ticket --;
                    System.out.println(threadName + "受理成功,已成功购票,余票: " + this.ticket);
                } else {
                    System.out.println(threadName + "受理失败,余票: " + this.ticket);
                }
                System.out.println();
            }

        }

    }
}

/****************************************************/

public class Main {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        Thread t1 = new Thread(ticket, "Window 1: ");
        Thread t2 = new Thread(ticket, "Window 2: ");
        Thread t3 = new Thread(ticket, "Window 3: ");

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

四、同步方法

同步方法:使用synchronized修饰的方法,线程A执行该方法的时候,其他线程只有等待。。

同步方法没有同步代码块灵活!

格式:

public synchronized void method(){
    可能会发生线程安全问题的代码。
}

同步方法的同步锁对象:

  • 对于非static,同步锁就是this对象。;
  • 对于static,同步锁是当前方法所在类的字节码对象( 类名.class,类模板)

五、Lock锁

包位置:java.util.concurrent.locks.Lock

比synchronized代码块和方法更流弊,更强大,更面向对象

加锁释放锁的方法:(省略public)

  • void lock() : 加同步锁(获取同步锁);
  • void unlock() : 释放同步锁;

代码示例,打印进度条:reentrant/riː'en trən t(不发音)/

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadLock implements Runnable{

    private int publicVariable = 50;
    Lock lock = new ReentrantLock();

    @Override
    public void run() {
        lock.lock();
        Random random = new Random();
        System.out.println("----别慌,先让我执行完! --> " + Thread.currentThread().getName());
        // 模拟一个进度条耍耍
        for (int i = 1; i <= publicVariable; i++) {
            System.out.print("[");

            int j = 0;
            while (j++ < i) System.out.print(">");
            while (j++ < publicVariable) System.out.print("-");

            System.out.print("]" + (i * 2) + "%");

            try { Thread.sleep(random.nextInt(100) + 1); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.print("\r");
        }
        System.out.println("----OK,我执行完了\n");
        lock.unlock();
    }
}

/*********************************/

public class Test {
    public static void main(String[] args) throws Exception {
        ThreadLock tl = new ThreadLock();

        Thread t1 = new Thread(tl, "线程 NO.1 ");
        Thread t2 = new Thread(tl, "线程 NO.2 ");
        Thread t3 = new Thread(tl, "线程 NO.3 ");

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

如果想使用Lock锁来使用obj.wait和obj.notify功能,如下:

Condition c = lock.newCondition();
c.await() :相当于wait
c.signal() :相当于notify
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容