多线程访问共享变量的时候会出现线程安全的问题
解决线程安全的问题:线程同步(同步代码块、同步方法、同步锁)
1.同步代码块
synchronized(同步监视器){ //需要访问的共享数据 } 同步监视器 : 俗称“锁”。可以使用任何对象充当。但是必须确定多个线程持有同一把锁(同一个对象)
2.同步方法
同步方法: ---- 隐式的锁 : this ----如果同步方法被静态(static)修饰后,隐式的锁是该类所属的字节码文件xxx.class(因为被static修饰,没有对象可调用此方法) public synchronized void show(){ //需要访问的共享数据 }
3.同步锁
public class MyRunnable implements Runnable { //static修饰 保证是共享资源 多个线程构造器传入同一个此对象则不必是static也可以 public static int tick = 100; //创建一个锁 static修饰 保证是一个锁 多个线程构造器传入同一个此对象则不必是static也可以 public static Lock lock = new ReentrantLock(); @Override public void run() { while (true) { //上锁 lock.lock(); try { if (tick > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { } tick--; System.out.println(Thread.currentThread().getName() + "完成售票,余票为 :" + tick); } } finally { //必须手动解锁 lock.unlock(); } } } }
public class TestLock { public static void main(String[] args) throws InterruptedException, ExecutionException { Thread thread1 = new Thread(new MyRunnable(),"aa"); thread1.start(); Thread thread2 = new Thread(new MyRunnable(),"bb"); thread2.start(); } }
public class TestThreadDeadLock { public static void main(String[] args) throws InterruptedException, ExecutionException { MyRunnable myRunnable = new MyRunnable(); //下面两个线程构造器都传入同一个myRunnable 则不必用上面说的static修饰共享变量 Thread thread1 = new Thread(myRunnable, "aa"); thread1.start(); Thread thread2 = new Thread(myRunnable, "bb"); thread2.start(); } }
打印结果
aa完成售票,余票为 :99 aa完成售票,余票为 :98 bb完成售票,余票为 :97 bb完成售票,余票为 :96 aa完成售票,余票为 :95 aa完成售票,余票为 :94 aa完成售票,余票为 :93 aa完成售票,余票为 :92 bb完成售票,余票为 :91 aa完成售票,余票为 :90 bb完成售票,余票为 :89 aa完成售票,余票为 :88 bb完成售票,余票为 :87 bb完成售票,余票为 :86 bb完成售票,余票为 :85 bb完成售票,余票为 :84 aa完成售票,余票为 :83 aa完成售票,余票为 :82 bb完成售票,余票为 :81 bb完成售票,余票为 :80 bb完成售票,余票为 :79 bb完成售票,余票为 :78 bb完成售票,余票为 :77 bb完成售票,余票为 :76 aa完成售票,余票为 :75 aa完成售票,余票为 :74 aa完成售票,余票为 :73 aa完成售票,余票为 :72 aa完成售票,余票为 :71 aa完成售票,余票为 :70 aa完成售票,余票为 :69 aa完成售票,余票为 :68 aa完成售票,余票为 :67 aa完成售票,余票为 :66 aa完成售票,余票为 :65 aa完成售票,余票为 :64 aa完成售票,余票为 :63 aa完成售票,余票为 :62 aa完成售票,余票为 :61 aa完成售票,余票为 :60 aa完成售票,余票为 :59 aa完成售票,余票为 :58 aa完成售票,余票为 :57 bb完成售票,余票为 :56 bb完成售票,余票为 :55 bb完成售票,余票为 :54 bb完成售票,余票为 :53 bb完成售票,余票为 :52 bb完成售票,余票为 :51 bb完成售票,余票为 :50 bb完成售票,余票为 :49 bb完成售票,余票为 :48 bb完成售票,余票为 :47 bb完成售票,余票为 :46 bb完成售票,余票为 :45 bb完成售票,余票为 :44 bb完成售票,余票为 :43 bb完成售票,余票为 :42 bb完成售票,余票为 :41 bb完成售票,余票为 :40 bb完成售票,余票为 :39 bb完成售票,余票为 :38 bb完成售票,余票为 :37 bb完成售票,余票为 :36 bb完成售票,余票为 :35 bb完成售票,余票为 :34 aa完成售票,余票为 :33 aa完成售票,余票为 :32 aa完成售票,余票为 :31 aa完成售票,余票为 :30 aa完成售票,余票为 :29 aa完成售票,余票为 :28 bb完成售票,余票为 :27 bb完成售票,余票为 :26 bb完成售票,余票为 :25 bb完成售票,余票为 :24 bb完成售票,余票为 :23 aa完成售票,余票为 :22 aa完成售票,余票为 :21 aa完成售票,余票为 :20 aa完成售票,余票为 :19 aa完成售票,余票为 :18 aa完成售票,余票为 :17 aa完成售票,余票为 :16 aa完成售票,余票为 :15 aa完成售票,余票为 :14 aa完成售票,余票为 :13 aa完成售票,余票为 :12 aa完成售票,余票为 :11 aa完成售票,余票为 :10 aa完成售票,余票为 :9 aa完成售票,余票为 :8 aa完成售票,余票为 :7 aa完成售票,余票为 :6 aa完成售票,余票为 :5 aa完成售票,余票为 :4 bb完成售票,余票为 :3 bb完成售票,余票为 :2 bb完成售票,余票为 :1 bb完成售票,余票为 :0
线程的死锁 : 不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁
匿名内部类写一个死锁
public class TestThreadDeadLock { public static void main(String[] args) throws InterruptedException, ExecutionException { //锁1 内部类如果引用外部类的变,则该变量必须为final,这是规定 final Object obj1 = new Object(); //锁2 final Object obj2 = new Object(); //线程1 new Thread(){ public void run(){ synchronized (obj1) { System.out.println("获取资源1,等待资源2......"); try { //线程1获取锁1后 睡一会(此时线程1占用锁1),等待线程2获取锁2(线程2占用锁2) Thread.sleep(200); } catch (InterruptedException e) { } synchronized (obj2) { System.out.println("--------------------------------"); } } } }.start(); // Thread.sleep(5000); //线程2 new Thread() { public void run() { synchronized (obj2) { System.out.println("获取资源2,等待资源1......"); synchronized (obj1) { System.out.println("****************************************"); } } } }.start(); } }
获取资源1,等待资源2...... 获取资源2,等待资源1......
代码写一个死锁
public class MyRunnable implements Runnable { //锁1 必须是static修饰的 代表同一把锁 public static Object obj1 = new Object(); //锁2 public static Object obj2 = new Object(); public boolean flag = true; @Override public void run() { if(flag){ synchronized (obj1) { System.out.println("获取资源1,等待资源2......"); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (obj2) { System.out.println("--------------------------"); } } }else{ synchronized (obj2) { System.out.println("获取资源2,等待资源1......"); synchronized (obj1) { System.out.println("**************************"); } } } } }
public class TestThreadDeadLock { public static void main(String[] args) throws InterruptedException, ExecutionException { MyRunnable myRunnable1 = new MyRunnable(); Thread thread1 = new Thread(myRunnable1); thread1.start(); MyRunnable myRunnable2 = new MyRunnable(); myRunnable2.flag = false; Thread thread2 = new Thread(myRunnable2); thread2.start(); } }
获取资源1,等待资源2...... 获取资源2,等待资源1......