1.什么是线程安全?
为什么有线程安全问题?
当多个线程同时共享,同一个全局变量或静态变量,做写的操作时,可能会发生数据冲突问题,也就是线程安全问题。但是做读操作是不会发生数据冲突问题。
2.线程安全解决办法:
问:如何解决多线程之间线程安全问题
答:使用多线程之间同步synchronized或使用锁(lock)。
问:为什么使用线程同步或使用锁能解决线程安全问题呢?
答:将可能会发生数据冲突问题(线程不安全问题),只能让当前一个线程进行执行。代码执行完成后释放锁,让后才能让其他线程进行执行。这样的话就可以解决线程不安全问题。
问:什么是多线程之间同步
答:当多个线程共享同一个资源,不会受到其他线程的干扰。
内置的锁
(解释:内置锁就是本类的Java字节码文件,谁能获取到该字节码文件谁就能拥有线程执行权)
Java提供了一种内置的锁机制来支持原子性
每一个Java对象都可以用作一个实现同步的锁,称为内置锁,线程进入同步代码块之前自动获取到锁,代码块执行完成正常退出或代码块中抛出异常退出时会释放掉锁
内置锁为互斥锁,即线程A获取到锁后,线程B阻塞直到线程A释放锁,线程B才能获取到同一个锁
内置锁使用synchronized关键字实现,synchronized关键字有两种用法:
1.修饰需要进行同步的方法(所有访问状态变量的方法都必须进行同步),此时充当锁的对象为调用同步方法的对象(解释:该方法能够被对象调用,说明是非静态同步方法,那么该锁就是this锁,静态同步方法是不能通过对象.方法名方式访问的)
2.同步代码块和直接使用synchronized修饰需要同步的方法是一样的,但是锁的粒度可以更细,并且充当锁的对象不一定是this,也可以是其它对象,所以使用起来更加灵活
多线程死锁
什么是多线程死锁?
答:同步中嵌套同步,导致锁无法释放(解释:多个线程产生了这样的问题:你要我的锁才能继续往下执行代码,我要你的锁才能继续往下执行代码,但是互相不释放锁资源,导致死锁的产生)
class Thread009 implements Runnable {
private int trainCount = 100;
private Object oj = new Object();
public boolean flag = true;
public void run() {
if (flag) {
while (trainCount > 0) {
synchronized (oj) {
try {
Thread.sleep(10);
} catch (Exception e) {
// TODO: handle exception
}
sale();
}
}
} else {
while (trainCount > 0) {
sale();
}
}
}
public synchronized void sale() {
synchronized (oj) {
try {
Thread.sleep(10);
} catch (Exception e) {
}
if (trainCount > 0) {
System.out.println(Thread.currentThread().getName() + "," + "出售第" + (100 - trainCount + 1) + "票");
trainCount--;
}
}
}
}
public class Test009 {
public static void main(String[] args) throws InterruptedException {
Thread009 threadTrain = new Thread009();
Thread t1 = new Thread(threadTrain, "窗口1");
Thread t2 = new Thread(threadTrain, "窗口2");
t1.start();
Thread.sleep(40);
threadTrain.flag = false;
t2.start();
}
}}
Threadlocal
什么是Threadlocal?
ThreadLocal提供一个线程的局部变量,访问某个线程拥有自己局部变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
ThreadLocal的接口方法
ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:
•void set(Object value)设置当前线程的线程局部变量的值。
• public Object get()该方法返回当前线程所对应的线程局部变量。
• public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
• protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。
ThreadLoca实现原理
ThreadLoca通过map集合
Map.put(“当前线程”,值);