- 什么是线程安全问题
- 当多个线程共享同一个全局变量,在做写的操作时,可能会发生线程安全问题。//
例子: 售卖火车票,多个窗口(多个线程)都在卖火车票数(共享全局变量)。每个窗口在售卖后都会修改票数(写的操作)
代码:/** * 窗口售卖火车票 */ class Thread03 implements Runnable{ private int count = 100; @Override public void run() { while (count > 0){ mail(); } } public synchronized void mail(){ if (count > 0) { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在出售第"+(100-count+1)+"票"); count--; } } } /** * 售卖火车票 * Create by wangxb * 2019-05-14 6:32 */ public class Test { public static void main(String[] args) { Thread03 th = new Thread03(); Thread t1 = new Thread(th); Thread t2 = new Thread(th); t1.start(); t2.start(); } }
- 什么是多线程的同步
- 多个线程共享同一个资源,不会收到其他线程的干扰。
- 如何解决线程安全问题
- 同步代码块:锁是任何obj对象
/** * 窗口售卖火车票 */ class Thread03 implements Runnable{ private int count = 100; private Object obj = new Object(); @Override public void run() { while (true){ mail(); } } public void mail(){ synchronized (obj){ if (count > 0) { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在出售第"+(100-count+1)+"票"); count--; } } } } public class Test { public static void main(String[] args) { Thread03 th = new Thread03(); Thread t1 = new Thread(th); Thread t2 = new Thread(th); t1.start(); t2.start(); } }
- 静态同步方法: 锁是当前类的字节码文件:Thread03.class
/** * 窗口售卖火车票 */ class Thread03 implements Runnable{ private static int count = 100; private Object obj = new Object(); @Override public void run() { while (true){ mail(); } } public static synchronized void mail(){ // 使用当前类的字节码文件: Thread03.class if (count > 0) { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在出售第"+(100-count+1)+"票"); count--; } } } public class Test { public static void main(String[] args) { Thread03 th = new Thread03(); Thread t1 = new Thread(th); Thread t2 = new Thread(th); t1.start(); t2.start(); } }
- 同步方法: 锁是this锁
/** * 窗口售卖火车票 */ class Thread03 implements Runnable{ private int count = 100; private Object obj = new Object(); @Override public void run() { while (true){ mail(); } } public synchronized void mail(){ // 使用this锁 if (count > 0) { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"正在出售第"+(100-count+1)+"票"); count--; } } } public class Test { public static void main(String[] args) { Thread03 th = new Thread03(); Thread t1 = new Thread(th); Thread t2 = new Thread(th); t1.start(); t2.start(); } }
-
什么是死锁
- 概念:同步中嵌套同步,导致无法释放
例子:class Thread01 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 Test { public static void main(String[] args) throws InterruptedException { Thread01 threadTrain = new Thread01(); Thread t1 = new Thread(threadTrain, "窗口1"); Thread t2 = new Thread(threadTrain, "窗口2"); t1.start(); Thread.sleep(40); threadTrain.flag = false; t2.start(); } }
- Threadlocal
- 什么是Threadlocal
是为了个每个线程提供一个局部变量,解决线程安全问题。class Demo{ // 生成序列号共享变量 public static Integer count = 0; public static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() { protected Integer initialValue() { return 0; }; }; public Integer getNum() { int count = threadLocal.get() + 1; threadLocal.set(count); return count; } } ######################原理############################## ThreadLoca实现原理 ThreadLoca通过map集合 Map.put(“当前线程”,值);
- Java内存模型
- 什么是java内存模型
简称(JMM), JMM决定了一个线程对共享变量写入的时候,是否对另一个线程可见。
JMM定义了线程和主内存之间的抽象关系,线程之间的共享变量存储在主内存,每个线程都有一个私有内存,私有内存存的是共享变量的副本 - 图例子:
上图:线程程A与线程B之间如要通信的话,必须要经历下面2个步骤:
a、首先,线程A把本地内存A中更新过的共享变量刷新到主内存中去。
b、然后,线程B到主内存中去读取线程A之前已更新过的共享变量。
- 图例2
本地内存A和B有主内存中共享变量x的副本。假设初始时,这三个内存中的x值都为0。线程A在执行时,把更新后的x值(假设值为1)临时存放在自己的本地内存A中。当线程A和线程B需要通信时,线程A首先会把自己本地内存中修改后的x值刷新到主内存中,此时主内存中的x值变为了1。随后,线程B到主内存中去读取线程A更新后的x值,此时线程B的本地内存的x值也变为了1。
- Volatile关键字
- 使用volatile关键字,能够解决A线程修改的共享变量(刷新主内存)对另一个线程可见。
- volatile可以保证线程的可见性,但不保证原子性
-
/** * 使用volatile修饰变量保证线程可见性 * Create by wangxb * 2019-05-14 20:44 */ class Thread01 implements Runnable{ public volatile boolean flag = true; // volatile可以将子线程修改的共享变量即使刷新主内存 @Override public void run() { System.out.println("子线程开始......"+flag); while (flag){ } System.out.println("子线程结束....."+flag); } public void setFlag(boolean flag){ this.flag = flag; } } public class Test { public static void main(String[] args) throws Exception { Thread01 th = new Thread01(); Thread t1 = new Thread(th); t1.start(); Thread.sleep(3000); th.setFlag(false); System.out.println("主线程获取flag---"+th.flag); } }
- volatile和synchronized的区别
volatile能保证线程的可见性,不能保证原子性(AtomicInteger保证原子性)
synchronizedvolatile能保证线程的可见性,也能保证原子性
volatile的性能优于synchronized
- AtomicInteger原子类
- AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减。解决了线程安全问题
- 主要应用在计数上
-
import java.util.concurrent.atomic.AtomicInteger; /** * AtomicInteger使用 * Create by wangxb * 2019-05-17 7:41 */ class Thread01 implements Runnable{ public static AtomicInteger count = new AtomicInteger(); public int set(){ try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } // 每次加1 == count++ return count.incrementAndGet(); } public void run() { while (true){ System.out.println(Thread.currentThread().getName()+"----"+set()); } } } public class Test { public static void main(String[] args) { Thread01 thread01 = new Thread01(); Thread th1 = new Thread(thread01); Thread th2 = new Thread(thread01); th1.start(); th2.start(); } }
- 原子类的实现原理:就是使用了cas无锁机制。我的另一篇文章有介绍
- automic相关类