多线程环境安全问题的判断标准(一定要三个同时满足)
是否是多线程环境
是否有共享数据
是否有多条语句操作(修改)共享数据
为什么出问题:
CPU的一次操作必须是原子性的,在一个时间点,CPU只能执行一条指令,而一条语句是由多条指令组成的,比如说i++指令,CPU要先执行i+1,然后将i+1的值赋给i,然后再输出。我们用一条语句来理解,比如下面的卖票程序,当A站点输出语句“A站点还剩88张票”,这个时候还没执行到i--语句,这是B站点抢占到CPU,因为i--还没有执行,B站点也会输出“B站点还剩88张票”,这就出现了线程安全问题。
线程方法:
public final int getPriority() 回去当前线程名
public final void setPriority(int newPriority) 设定当前线程名
public static void sleep(long millis) 线程休眠
public final void join() 线程加入 意思是加入的线程优先运行,运行结束后才会轮到下一个线程 注意:必须先开启该线程才能加入线程
public static void yield() 线程礼让 目的时尚线程抢占更加均衡
public final void setDaemon(boolean on) 后台线程:守护线程,精灵线程
public final void stop():中断线程 不建议使用
public void interrupt(): 中断线程
如何正确地停止一个线程?
A:①、使用退出标志,使线程正常退出,也就是当 run 方法完成后线程终止;
②、使用 interrupt 方法中断线程;
③、使用 stop 方法强行终止,但是不推荐使用,因为 stop 和 suspend 以及 resume 一样存在死锁威胁,并且都是过期作废的方法。
第一种,继承Thread创建多线程,同步方法,静态锁obj对象,使用同步代码块。
两者不同点红色标注
public class MyThread extends Thread{ static int i=100 ; static Object obj=new Object(); public MyThread() { super(); } public MyThread(String name) { super(name); } @Override public void run() { while(i>0){ synchronized (obj) {//obj对象必须静态,否则两个对象调用的obj不相同,必须保证只有一把锁 System.out.println(Thread.currentThread().getName()+"抢到票,还剩"+i+"张票"); i--; } } } } public class ThreadTest { public static void main(String[] args) { MyThread thread1 = new MyThread("A站点"); MyThread thread2 = new MyThread("B站点"); thread1.start(); thread2.start(); } } 执行结果 B站点抢到票,还剩100张票 A站点抢到票,还剩99张票 A站点抢到票,还剩98张票 A站点抢到票,还剩97张票 A站点抢到票,还剩96张票 A站点抢到票,还剩95张票 A站点抢到票,还剩94张票 A站点抢到票,还剩93张票 A站点抢到票,还剩92张票 A站点抢到票,还剩91张票 A站点抢到票,还剩90张票 A站点抢到票,还剩89张票 A站点抢到票,还剩88张票 A站点抢到票,还剩87张票 A站点抢到票,还剩86张票 A站点抢到票,还剩85张票 A站点抢到票,还剩84张票 A站点抢到票,还剩83张票 A站点抢到票,还剩82张票
第二种 实现runnable接口
1 public class MyRunnable implements Runnable { 2 int i=100; 3 Object obj =new Object(); 4 @Override 5 public void run() { 6 while(i>0) { 7 //因为线程虽然有两个 但是多态得到的子类对象只有一个 所以不用静态obj 8 //在这里使用代码块而不使用同步关键字修饰方法是因为同步方法,那一个对象会把这个方法执行完才会跳出循环,那就没票了 9 //使用obj和this是一个意思 10 synchronized(this) { 11 System.out.println(Thread.currentThread().getName()+"抢到票,还剩"+i+"张票"); 12 i--; 13 try { 14 Thread.sleep(100);//加个休眠模拟网络延迟,不知道为什么不加休眠一个线程能抢光所有的票 15 } catch (InterruptedException e) { 16 // TODO Auto-generated catch block 17 e.printStackTrace(); 18 } 19 } 20 } 21 } 22 } 23 24 public static void main(String[] args) { 25 MyRunnable runnable =new MyRunnable(); 26 Thread thread1 = new Thread(runnable,"A站点"); 27 Thread thread2 = new Thread(runnable,"B站点"); 28 thread2.start(); 29 thread1.start(); 30 } 31 }