三 多线程执行的共享数据和非共享数据:
共享数据:就是每个线程执行的时候共享数据使用,比如这个线程一个为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:4
B:count:4
A:count:4
B:count:3
C:count:3
C:count:2
C:count:1
C:count:0
B:count:2
A:count:3
B:count:1
A:count:2
B:count:0
A:count:1
A: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:2
C:count:1
或者:
A:count:2
B:count:2
C: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:2
C: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里的代码