自定义的线程类中实例变量针对其他线程可以有共享和不共享之分,这在多个线程之间进行交互时是很重要的一个技术点
1、 不共享数据的情况
public class MyThread extends Thread { private int count = 5; public MyThread(String name) { super(); this.setName(name); } @Override public void run() { super.run(); while (count > 0) { count--; System.out.println("由" + Thread.currentThread().getName() + "计算,count:" + count); } } public static void main(String[] args) { MyThread a = new MyThread("A"); MyThread b = new MyThread("B"); MyThread c = new MyThread("C"); a.start(); b.start(); c.start(); } }
运行结果:
由A计算,count:4 由A计算,count:3 由A计算,count:2 由A计算,count:1 由A计算,count:0 由B计算,count:4 由C计算,count:4 由B计算,count:3 由C计算,count:3 由C计算,count:2 由C计算,count:1 由C计算,count:0 由B计算,count:2 由B计算,count:1 由B计算,count:0
一共三个线程,每个线程有自己的count变量,自己减少自己的count变量,这种情况变量不共享,此示例并不存在多个线程访问同一个变量的情况
2、共享数据的情况
public class MyThread extends Thread { private int count = 5; @Override public void run() { while (count > 0) { count--; System.out.println("由" + Thread.currentThread().getName() + "计算,count:" + count); } } public static void main(String[] args) { MyThread mythread = new MyThread(); Thread a = new Thread(mythread, "A"); Thread b = new Thread(mythread, "B"); Thread c = new Thread(mythread, "C"); Thread d = new Thread(mythread, "D"); Thread e = new Thread(mythread, "E"); a.start(); b.start(); c.start(); d.start(); e.start(); } }
运行结果:
由A计算,count:3 由A计算,count:2 由A计算,count:1 由A计算,count:0 由B计算,count:3
A和B线程都打印出过count的值都是3,说明A和B同事对count进行处理,产生了“非线程安全”问题。我们预期是依次递减的
针对多线程共享数据出现非线程安全情况,需要使多个线程之间进行同步,也就是按顺序排队的方式进行减1操作
public class MyThread extends Thread { private int count = 5; @Override //synchronized可以在任意对象及方法上加锁,而加锁的这段代码称为“互斥区”或“临界区” public synchronized void run() { while (count > 0) { count--; System.out.println("由" + Thread.currentThread().getName() + "计算,count:" + count); } } public static void main(String[] args) { MyThread mythread = new MyThread(); Thread a = new Thread(mythread, "A"); Thread b = new Thread(mythread, "B"); Thread c = new Thread(mythread, "C"); Thread d = new Thread(mythread, "D"); Thread e = new Thread(mythread, "E"); a.start(); b.start(); c.start(); d.start(); e.start(); } }
当一个线程运行调用run()前,先判断run方法有没有被上锁,如果上锁,说明其他线程线程正在调用run方法。这样也就实现了排队调用run()方法的目的,也达到了按顺序对count变量减一的效果
当一个线程想要执行同步里面的代码时,线程首先尝试去拿这把锁,如果能够拿到这把锁,那么这个线程可以执行synchronize里面的代码。如果不能拿到这把锁,那么这个线程会不断尝试拿这把锁,直到能够拿到为止,而且是有多个线程同时去争这把锁
非线程安全:是指多个线程对同一个对象中的同一个实例变量进行操作时会出现值被更改、值不同步的情况,进而影响程序的执行流程。