线程、进程、多线程

一个进程可以有多个线程,如一个视频,可以同时听声音、看图像、看弹幕等等。

  • 说起进程,就不得不说下程序。程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
  • 进程则是执行春哥徐的一次执行过程,它是一个动态的概念。是系统资源分配的单位。
  • 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的单位。

注意:很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器。如果是模拟出来的多线程,即在一个CPU的情况下,在同一个时间点,CPU只能执行一个代码,因为切换得很快,所以就有了同时执行的错觉。

核心概念

  • 线程就是独立的执行路径;
  • 在程序运行时,即时没有自己创建线程,后台也会有多个线程,如主线程,GC线程;
  • main()称之为主线程,为系统的入口,用于执行整个程序;
  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能认为干预的;
  • 对同一份资源操作时,会存在资源抢夺的问题,需要假如并发控制;
  • 线程会带来额外的开销,如CPU调度时间,并发控制开销;
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致;

三种创建线程的方式:

代码实现的话,不建议使用“继承Thread类”,避免OOP单继承局限性,推荐使用“实现Runnable接口”,因为它能避免单继承局限性,灵活方便,方便同一个对象被多个线程使用。如下:

代码实现 方式一:

 1 package com.huolongluo.coindemo.morethread.sub1;
 2 
 3 /**
 4  * Created by 火龙裸 on 2019/11/9.
 5  * desc   : 创建线程方式一:继承Thread类,重写run方法,调用start开启线程。
 6  *
 7  * 总结:线程开启不一定立即执行,由CPU调度执行
 8  * version: 1.0
 9  */
10 public class TestThread1 extends Thread {
11     @Override
12     public void run() {
13         //run方法线程体
14         for (int i = 0; i < 20; i++) {
15             System.out.println("我在看代码--- " + i);
16         }
17     }
18 
19     public static void main(String[] args) {
20         //main线程,主线程
21 
22         //创建一个线程对象
23         TestThread1 testThread1 = new TestThread1();
24         //调用start()方法开启线程
25         //注意这个地方,假如调用run方法,虽然会执行run里面的代码,但这是调用,一定会先执行完run里面的代码,最后才打印“今天又是奋斗的一天”,多个线程同时执行,应该使用start方法,这样它们才会交替执行。
26         testThread1.start();
27 
28         for (int i = 0; i < 20; i++) {
29             System.out.println("今天又是奋斗的一天-- " + i);
30         }
31     }
32 }

代码实现 方式二:

 1 package com.huolongluo.coindemo.morethread.sub1;
 2 
 3 /**
 4  * Created by 火龙裸 on 2019/11/9.
 5  * desc   : 创建线程方式二:实现Runnable接口,重写run方法,执行线程需要丢入runnable接口的实现类,调用start方法。
 6  * version: 1.0
 7  */
 8 public class TestThread2 implements Runnable {
 9     @Override
10     public void run() {
11         //run方法线程体
12         for (int i = 0; i < 20; i++) {
13             System.out.println("我在看代码--- " + i);
14         }
15     }
16 
17     public static void main(String[] args) {
18         //创建runnable接口的实现类对象
19         TestThread2 testThread2 = new TestThread2();
20         //创建线程对象,通过线程对象来开启我们的线程,代理
21 //        Thread thread = new Thread(testThread2);
22 //        thread.start();
23         new Thread(testThread2).start();
24         for (int i = 0; i < 20; i++) {
25             System.out.println("今天又是奋斗的一天-- " + i);
26         }
27     }
28 }

当需要多个线程操作同一个对象是,那就需要想办法处理“并发问题”,代码示例如下:

 1 package com.huolongluo.coindemo.morethread.sub1;
 2 
 3 /**
 4  * Created by 火龙裸 on 2019/11/9.
 5  * desc   : 多线程同时操作同一个对象
 6  * 买火车票例子
 7  * <p>
 8  * 多个线程操作同一个资源对象的情况下,线程不安全,数据紊乱。
 9  * version: 1.0
10  */
11 public class TestThread4 implements Runnable {
12 
13     //票数
14     private int ticketNums = 10;
15 
16     @Override
17     public void run() {
18         while (true) {
19             if (ticketNums <= 0) {
20                 break;
21             }
22             //模拟延时
23             try {
24                 Thread.sleep(200);
25             } catch (InterruptedException e) {
26                 e.printStackTrace();
27             }
28             System.out.println(Thread.currentThread().getName() + " 拿到了第:" + ticketNums-- + " 张票");
29         }
30     }
31 
32     public static void main(String[] args) {
33 
34         TestThread4 testThread4 = new TestThread4();
35 
36         new Thread(testThread4, "小明").start();
37         new Thread(testThread4, "老师").start();
38         new Thread(testThread4, "黄牛党").start();
39     }
40 }

执行结果:

从执行结果中看到,出票顺序出现异常,第6张票同时被两个人拿到,而且还出现第0张票。这就是需要注意处理的多线程并发问题。

猜你喜欢

转载自www.cnblogs.com/huolongluo/p/11825327.html