三 多线程执行的共享数据和非共享数据:
共享数据:就是每个线程执行的时候共享数据使用,比如这个线程一个为5的数据,减少为4之后,另一个线程执行拿到的数据是4,两个线程执行的数据是共享的。
非共享数据:各个线程执行的数据不受其他线程数据的改变而改变。
1 非共享数据:
1 package link.summer7c.test; 2 3 public class Test{ 4 public static void main(String[] args){ 5 MyThread2 a=new MyThread2("A"); 6 MyThread2 b=new MyThread2("B"); 7 MyThread2 c=new MyThread2("C"); 8 a.start(); 9 b.start();10 c.start();11 }12 }13 class MyThread2 extends Thread{14 private int count=5;15 public MyThread2(String name){16 super();17 this.setName(name);18 }19 public void run(){20 super.run();21 while(count>0){22 count--;23 System.out.println(this.currentThread().getName()+":count:"+count);24 }25 }26 }
程序运行结果为:
C:count:4B:count:4A:count:4B:count:3C:count:3C:count:2C:count:1C:count:0B:count:2A:count:3B:count:1A:count:2B:count:0A:count:1A:count:0
从结果我们可以看见,3个线程的数据之间互不影响,变量减少按照各自的减法进行。这就是非共享的数据,这种做法通常在一些多线程并发操作中使用,各个数据没有相互影响。
2 共享数据:
各个线程之间的数据是共享的,他们的数据受其他线程的运行而影响。
1 package link.summer7c.test; 2 3 public class Test{ 4 public static void main(String[] args){ 5 MyThread3 myThread=new MyThread3(); 6 Thread a=new Thread(myThread,"A"); 7 Thread b=new Thread(myThread,"B"); 8 Thread c=new Thread(myThread,"C"); 9 a.start();10 b.start();11 c.start();12 }13 }14 class MyThread3 extends Thread{15 private int count=4;16 public void run(){17 super.run();18 count--;19 System.out.println(this.currentThread().getName()+":count:"+count);20 }21 }
运行结果有很多种:
A:count:3
B:count:2C:count:1或者:
A:count:2
B:count:2C:count:1这种运行结果可能会发现有些问题,就是出现了相同的数据。
这个之后来讨论。
构造方法public Thread(Runnable target, String name)
共享数据的main方法中并不是new了多个对象,而是new个一个我们的类,然后new了3个Thread对象,调用了public Thread(Runnable target, String name)构造方法。
共享数据的时候还要不能出现循环,如果一个线程开始循环,那么其他循环就得不到运行的机会了。
三 线程安全的问题
在共享数据的时候,我们会看到多个运行及结果很奇特,比如在运行的时候会出现2个相同的数据,这就牵扯到了线程安全的问题,如果在多线程中出现了:
A:count:2
B:count:2C:count:1这种情况,就称作线程不安全。举个例子,我们再抢火车票,每个客户都是一个线程,那么我们需要线程之间是安全的,不然就会发生两个座位同时被买走的可能性,发生这样的情况很不好。为了解决线程安全性我们可以使用同步锁,也就是每个线程之间要同步数据,不能发生线程之间不同步导致的线程不安全情况。多线程之间的同步可以通过在run方法之前加入synchronized关键字来实现,这样就不会出现两个数据相同的情况了。
class MyThread3 extends Thread{ private int count=4; synchronized public void run(){ super.run(); count--; System.out.println(this.currentThread().getName()+":count:"+count); }}
synchronized可以在任意对象和方法上加锁,加锁的代码称为“互斥区”或者临界区。加上锁之后线程会是这样的:
程序运行->拿锁->如果拿到锁了执行synchronized里的代码
->如果没有拿到就不断的尝试知道拿到->执行synchronized里的代码
=========================================