线程安全的定义:当多个线程去访问同一个类(对象或方法)的时候,该类都能表现出正常的行为(与自己预想的结果一致),那我们就可以所这个类是线程安全的。
示例:我们写一个线程,继承thread类(也可以实现runnable接口),重写run方法,然后在main方法里面实例一个类对象,分别新建5个线程,注入类对象,分别启动5个 线程。
package com.lzf.thread;
public class MyThread extends Thread {
private int num = 8;
public void run() {
num--;
System.out.println("num:值" + num + ",thread的name:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread, "t1");
Thread t2 = new Thread(myThread, "t2");
Thread t3 = new Thread(myThread, "t3");
Thread t4 = new Thread(myThread, "t4");
Thread t5 = new Thread(myThread, "t5");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
运行结果如下:
num:值6,thread的name:t1
num:值6,thread的name:t2
num:值5,thread的name:t4
num:值4,thread的name:t3
num:值3,thread的name:t5
很显然,跟我们的预想结果不一致,我们预想num的值是7,6,5,4,3,这就是出现了线程不安全的结果。
多个线程在访问该对象的方法时,需要通过竞争锁来执行这段方法 我们可以在run方法上synchronized锁修饰符,即一次只允许一个对象线程进行访问,其他线程进入锁竞争状态,等待当前进入run方法的线程执行结束。
package com.lzf.thread;
public class MyThread extends Thread {
private int num = 8;
public synchronized void run() {
num--;
System.out.println("num:值" + num + ",thread的name:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
Thread t1 = new Thread(myThread, "t1");
Thread t2 = new Thread(myThread, "t2");
Thread t3 = new Thread(myThread, "t3");
Thread t4 = new Thread(myThread, "t4");
Thread t5 = new Thread(myThread, "t5");
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
运行结果如下:
num:值7,thread的name:t1
num:值6,thread的name:t5
num:值5,thread的name:t2
num:值4,thread的name:t4
num:值3,thread的name:t3
与我们预期的结果一致,有人可能会有疑问,为毛不是按照我们代码的写的线程顺序执行呢?打印出的线程名不是t1,t2,t3,t4,t5呢?一定要注意,在多线程编程中,线程的执行顺序全部由cpu进行动态分配,不一定会按照我们代码所写的顺序进行执行。锁的竞争会不会影响性能,比如1000个线程同时执行,1个线程正在执行方法,999的线程正在竞争获取锁,这个问题留在后面进行讲解,后续会持续更新相关知识。
本博客都是作者在学习后进行的知识笔记或总结,部分内容可能与其他作者的博客内容相似或相同。