一线程的初步认识

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一线程的初步认识相关的知识,希望对你有一定的参考价值。

      在上周去面试的时候,面试官问了我一个关于线程池的问题,当时没有答上来。所以,回来了之后决定重新学习一下多线程。
      这也是本人第一次写博客,之前一直想写,但是,一直没有搞清楚博客园的博客系统是怎么玩的。这次,到网上看到了一些关于博客园的小技巧,正好最近在学习多线程,拿来练练手。

1.创建线程

 1 public class Demo {
 2     public static void main(String [] args){
 3         //方法一:通过继承Thread类,当调用start()方法时,就会启动一个线程去执行run方法里面的代码。这里直接使用内部类。
 4         new Thread(){
 5             public void run() {
 6                 System.out.println(Thread.currentThread().getName());
 7             };
 8         }.start();
 9 
10         //方法二:实现Runnable接口
11         Runnable r = new Runnable() {
12             @Override
13             public void run() {
14                 System.out.println(Thread.currentThread().getName());
15             }
16         };
17         new Thread(r).start();
18 
19         /**
20          * 不管用哪种方法调用线程的启动都是调用Thread类的start()方法。
21          * 只是执行任务由可以是Thread中run方法,也可以是Runnable接口的run方法。
22          */
23     }
24 }

2.线程安全

 1 public class Demo2 {
 2     private int value = 1;
 3 
 4     public int getNext(){
 5         return value++;
 6     }
 7 
 8     public static void main(String[] args) {
 9         final Demo2 demo = new Demo2();
10         Runnable r = new Runnable() {
11             @Override
12             public void run() {
13                 System.out.println(demo.getNext());
14             }
15         };
16         /**
17          * 当少量线程同时访问getNext()方法时,程序不会有什么问题。
18          * 但是如果并发量较大(这里模拟500个线程同时访问),得到结果往往不是想要的结果。
19          */
20         for(int i = 0 ;i <500;i++){
21             new Thread(r).start();
22         }
23     }
24 
25 }

 

出现问题的原因是:value++不是一个原子操作,或者说该操作不具备原子性。
原子性:原子是世界上最小的单位,具有不可分割性。在我们编程的世界里,某个操作如果不可分割我们就称之为该操作具有原子性。i=0不可能再分割,所以该操作具有原子性。但是getNext()方法的value++,是可以分割的,这实际上有个“读取-修改-写入”的操作序列。如果一个操作具有原子性,那也就不会有线程安全问题。做完了就做完了!但是一个操作不具有原子性,那么,在这个操作在执行的过程中,有可能被外部所改变。

解析:这个类有一个字段value,并且提供了可改变字段的方法,所以该对象的状态是可变的。上面程序多个线程同时访问getNext()方法时。如果线程是按顺序执行,正确的执行方式是第一条线程读取value的值并打印出来,然后对齐值进行自增操作。然后下一条线程再读取value值,接着打印、自增...,结果值应该是 1、2、3、4、5...500  按顺序打印出来,我们希望的结果也是这样。但是,多线程之间的操作是交替执行的,当第一个线程读取value值时,第二个线程也有可能在做读取value值的操作,第三个也可能做着同样的操作。这样,各个线程之间得到的值就有可能相同,而不是理想中按照顺序对value的值进行递增。

解决办法:在run方法上加synchronized(当然也可以在getNext方法上加,只是锁对象不一样而已)

 1 public class Demo2 {
 2     private int value = 1;
 3 
 4     public int getNext(){
 5         return value++;
 6     }
 7 
 8     public static void main(String[] args) {
 9         final Demo2 demo = new Demo2();
10         Runnable r = new Runnable() {
11             @Override
12             public synchronized void run() {
13                 System.out.println(demo.getNext());
14             }
15         };
16         /**
17          * 当少量线程同时访问getNext()方法时,程序不会有什么问题。
18          * 但是如果并发量较大(这里模拟500个线程同时访问),得到结果往往不是想要的结果。
19          */
20         for(int i = 0 ;i <500;i++){
21             new Thread(r).start();
22         }
23     }
24 
25 }

 

以上是关于一线程的初步认识的主要内容,如果未能解决你的问题,请参考以下文章

线程初步认识

线程初步认识

JAVA-初步认识-第十二章-JVM中的多线程分析

JAVA-初步认识-第十三章-多线程(线程安全问题的现象)

JAVA-初步认识-第十四章-多线程-停止线程方式-定义标记

JAVA-初步认识-第十四章-多线程(守护线setDaemon)