大数据之路week03--day05(线程 I)

真的,身体这个东西一定要爱护好,难受的时候电脑都不想去碰,尤其是胃和肾。。。

这两天耽误了太多时间,今天好转了立刻学习,即刻不能耽误!、

话不多说,说正事:

1、多线程(理解)

  (1)多线程:一个应用程序有多条执行路径

      进程:正在执行的应用程序

      线程:进程的执行单元,或者说是执行路径

      单线程:一个应用程序只有一条执行路径

      多线程:一个应用程序有多条执行路径

    多进程的意义何在?

      提高CPU的使用率

    多线程的意义何在?

      提高应用程序的使用率

问题:

  一边玩游戏,一边听歌时同时进行的吗?

    不是,因为单CPU在某一个时间点上只能做一件事。

    而我们在玩游戏,或者听歌的时候,是CPU在做着程序间的高效切换让我们觉得是同时进行的。

  

  (2)Java程序的运行原理及JVM的启动是多线程的吗?

    A:Java命令去启动JVM,JVM会启动一个进程,该进程会启动一个主线程。

    B: JVM的启动是多线程的,因为它最低有两个线程启动了,主线程垃圾回收线程

      两个词汇:并行和并发

        并行是逻辑上同时发生,指在某一个时间段内同时运行多个程序。

        并发是物理上同时发生,指在某一个时间点同时运行多个程序。

      高并发:在某个时间点上很多人去访问一个(大数据)

  (3)多线程的实现方案

    A: 继承Thread类

      步骤:   

        1、自定义类MyThread继承Thread类

        2、MyThread类里面重写run()

        3、创建对象

        4、启动线程

MyThread类

 1 package com.wyh.Thread01;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午3:04:30
 6 */
 7 public class MyThread extends Thread {
 8     @Override
 9     public void run() {
10         for(int x = 0; x<500;x++) {
11             System.out.println(x);
12         }
13     }
14 
15 }

测试类:

 1 package com.wyh.Thread01;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午3:05:18
 6 */
 7 public class ThreadDemo01 {
 8     public static void main(String[] args) {
 9         MyThread my1 = new MyThread();
10         MyThread my2 = new MyThread();
11         
12         my1.start();
13         my2.start();
14     }
15     
16 
17 }

    B: 实现Runnable接口

        1、自定义类MyThread实现Runnable接口

        2、MyThread类里面重写run()

        3、创建对象

        4、创建Thread对象,把MyThread对象当作参数传入

        5、启动线程

Runnable类

 1 package com.wyh.Thread04;
 2 
 3 /**
 4  * @author WYH
 5  * @version 2019年11月22日 下午7:00:06
 6  */
 7 public class MyRunnable implements Runnable {
 8 
 9     @Override
10     public void run() {
11         for (int x = 1; x <= 500; x++) {
12             System.out.println(Thread.currentThread().getName() + "--" + x);
13         }
14 
15     }
16 
17 }

测试类:

 1 package com.wyh.Thread04;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午7:01:07
 6 */
 7 public class MyRunnableDemo {
 8     public static void main(String[] args) {
 9         MyRunnable my = new MyRunnable();
10         Thread t1 = new Thread(my,"王友虎");
11         Thread t2 = new Thread(my,"赵以浩");
12         
13         t1.start();
14         t2.start();
15         
16     }
17 
18 }

  (4)线程的调度和优先级问题

    A:线程的调度

      a:分时调度

      b:抢占式调度(Java采用的是该调度方式)

    B:获取和设置线程的优先级

      a:默认是5

      b:范围是1-10

  (5)线程的控制(常见方法)

    A:休眠线程(测试类在这不写,基本不变)

 1 package com.wyh.Thread03;
 2 
 3 import java.util.Date;
 4 
 5 /** 
 6 * @author WYH
 7 * @version 2019年11月22日 下午3:04:30
 8 */
 9 public class ThreadSleep extends Thread {
10     public ThreadSleep() {
11         super();
12         // TODO Auto-generated constructor stub
13     }
14 
15     public ThreadSleep(String name) {
16         super(name);
17         // TODO Auto-generated constructor stub
18     }
19 
20     @Override
21     public void run() {
22         for(int x = 0; x<500;x++) {
23             System.out.println(getName()+x+" 日期:"+new Date());
24             //睡眠1秒
25             try {
26                 Thread.sleep(1000);
27             } catch (InterruptedException e) {
28                 // TODO Auto-generated catch block
29                 e.printStackTrace();
30             }
31             
32         }
33     }
34 
35 }

    B:加入线程(run方法类不变)

 1 package com.wyh.Thread03;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午3:05:18
 6 * 
 7 * join 为了让某些线程执行完毕,才能执行其他的(线程加入)
 8 * 
 9 * 
10 * 
11 */
12 public class ThreadJoinDemo {
13     public static void main(String[] args) {
14         
15         ThreadPriority my1 = new ThreadPriority("王友虎");
16         ThreadPriority my2 = new ThreadPriority("李宏灿");
17         ThreadPriority my3 = new ThreadPriority("齐博源");
18         
19         my1.start();
20         try {
21             my1.join();
22         } catch (InterruptedException e) {
23             // TODO Auto-generated catch block
24             e.printStackTrace();
25         }
26         
27         my2.start();
28         my3.start();
29         
30     }
31     
32 
33 }

    C:礼让线程(省略测试类代码)

 1 package com.wyh.Thread03;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午4:28:15
 6 */
 7 public class ThreadYield extends Thread {
 8     public ThreadYield() {
 9         super();
10         // TODO Auto-generated constructor stub
11     }
12 
13     public ThreadYield(String name) {
14         super(name);
15         // TODO Auto-generated constructor stub
16     }
17 
18     @Override
19     public void run() {
20         for(int x = 0; x<200;x++) {
21             System.out.println(getName()+x);
22             Thread.yield();
23         }
24     }
25 }

    D:后台线程(省略继承类的代码)//注意!!!!必须在启动前声明

 1 package com.wyh.Thread03;
 2 
 3 /**
 4  * @author WYH
 5  * @version 2019年11月22日 下午4:42:16
 6  * 
 7  * 守护线程
 8  * 
 9  * 理解:坦克大战,黄绿坦克守护家,家没了,坦克也没了
10  * 
11  */
12 public class ThreadDeamonDemo {
13     public static void main(String[] args) {
14         ThreadDeamon td1 = new ThreadDeamon("关羽");
15         ThreadDeamon td2 = new ThreadDeamon("张飞");
16         
17         
18         //注意!!!!必须在启动前声明
19         td1.setDaemon(true);
20         td2.setDaemon(true);
21 
22         td1.start();
23         td2.start();
24 
25         
26         
27         
28         Thread.currentThread().setName("刘备");
29         for (int x = 0; x < 5; x++) {
30             System.out.println(Thread.currentThread().getName() + x);
31         }
32     }
33 
34 }

    E:终止线程(不推荐使用stop,而且该方法已经过时,推荐使用interrupt)

继承类:

 1 package com.wyh.Thread03;
 2 
 3 import java.util.Date;
 4 
 5 /** 
 6 * @author WYH
 7 * @version 2019年11月22日 下午4:57:38
 8 */
 9 public class ThreadStop extends Thread{
10     @Override
11     public void run() {
12         System.out.println("时间:"+new Date());
13         
14         //睡眠10秒钟
15         try {
16             Thread.sleep(10000);
17         } catch (InterruptedException e) {
18             System.err.println("睡眠被意外中止!!");
19         }
20         
21         System.out.println("时间:"+new Date());
22         
23     }
24 }

测试类:

 1 package com.wyh.Thread03;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午5:00:21
 6 */
 7 public class ThreadStopDemo {
 8     public static void main(String[] args) {
 9         ThreadStop ts = new ThreadStop();
10         ts.start();
11         
12         try {
13             Thread.sleep(3000);
14 //            ts.stop();  //不建议使用  因为后面的代码无法执行
15             ts.interrupt();
16         } catch (InterruptedException e) {
17             e.printStackTrace();
18         }
19         
20         
21     }
22 
23 }

  (6)线程的生命周期(图解)

  (7)电影院卖票程序的实现

      A:继承Thread类

继承类:

 1 package com.wyh.Thread05;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午7:33:38
 6 */
 7 public class SellTicket extends Thread {
 8     private static int tickets = 100;
 9     
10     @Override
11     public void run() {
12         while(true) {
13             if(tickets>0) {
14                 System.out.println(getName()+"窗口正在售卖第"+(tickets--)+"张票。。");
15             }
16             
17         }
18     }
19 }

测试类:

 1 package com.wyh.Thread05;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午7:36:19
 6 */
 7 public class TicketDemo {
 8     public static void main(String[] args) {
 9         //先创建多个线程
10         SellTicket st1 = new SellTicket();
11         SellTicket st2 = new SellTicket();
12         SellTicket st3 = new SellTicket();
13         
14         //给多个线程起名字’
15         st1.setName("窗口1");
16         st2.setName("窗口2");
17         st3.setName("窗口3");
18         
19         st1.start();
20         st2.start();
21         st3.start();
22         
23         
24         
25     }
26 
27 }

      B:实现Runnable接口

实现Runnable接口类:

 1 package com.wyh.Thread05;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午7:42:37
 6 */
 7 public class SellTicket_Runnable implements Runnable {
 8     private int tickets = 100;
 9 
10     @Override
11     public void run() {
12         while(true) {
13             if(tickets>0) {
14                 System.out.println(Thread.currentThread().getName()+"窗口正在售卖第"+(tickets--)+"张票。。");
15             }
16         }
17 
18     }
19 
20 }

测试类:

 1 package com.wyh.Thread05;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午7:43:48
 6 */
 7 public class SellTicket_RunnableDemo {
 8     public static void main(String[] args) {
 9         SellTicket_Runnable sr = new SellTicket_Runnable();
10         
11         Thread t1 = new Thread(sr,"窗口1");
12         Thread t2 = new Thread(sr,"窗口2");
13         Thread t3 = new Thread(sr,"窗口3");
14         
15         t1.start();
16         t2.start();
17         t3.start();
18         
19     }
20 
21 }

  (8)电影院卖票程序出的问题

    A:为了更加符合真实场景,加入了休眠100毫秒。

    B:买票问题

      a:同票被多次出售

      b:出现0票和负数票

  (9)多线程安全问题的原因(也是我们以后判断一个程序是否有安全问题的依据)

    A:是否有多线程环境

    B:是否有共享数据

    C:是否有多条语句操作共享数据

  (10)同步解决线程安全问题(以解决上面售票的为例解决)

    A:同步代码块

        synchronized(对象){

          需要被同步的代码;

        }

      这里的对象可以是任意对象(充当锁的作用,下面也是相同作用)

实现接口类:(测试类代码不变)

 1 package com.wyh.Thread06_tickets;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午7:42:37
 6 */
 7 public class SellTicket_Runnable implements Runnable {
 8     private int tickets = 300;
 9     private Object obj = new Object();  //如同一把锁 多个线程共用一把锁,把对共享数据的操作包起来
10 
11     @Override
12     public void run() {
13         while(true) {
14             synchronized(obj) {
15                 if(tickets>0) {
16                     try {
17                         Thread.sleep(30);
18                     } catch (InterruptedException e) {
19                         // TODO Auto-generated catch block
20                         e.printStackTrace();
21                     }
22                     System.out.println(Thread.currentThread().getName()+"窗口正在售卖第"+(tickets--)+"张票。。");
23                 }
24             }
25             
26         }
27 
28     }
29 
30 }

    B:同步方法

      把同步放在方法上。

      这里的锁对象是 this

实现接口类:(测试类代码不变)

 1 package com.wyh.Thread07_tickets2_同步方法静态;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午7:42:37
 6 */
 7 public class SellTicket_Runnable implements Runnable {
 8     private int tickets = 300;
 9     private int x = 0;
10     
11     //用obj对象做锁
12     private Object obj = new Object();  //如同一把锁 多个线程共用一把锁,把对共享数据的操作包起来
13     
14 
15     @Override
16     public void run() {
17         if(x%2==0) {
18             while(true) {
19                 synchronized(this) {
20                     if(tickets>0) {
21                         try {
22                             Thread.sleep(30);
23                         } catch (InterruptedException e) {
24                             // TODO Auto-generated catch block
25                             e.printStackTrace();
26                         }
27                         System.out.println(Thread.currentThread().getName()+"窗口正在售卖第"+(tickets--)+"张票。。");
28                     }
29                 }
30                 
31             }
32         }else {
33                 synchronize();
34         }
35         
36 
37     }
38 
39 
40     private synchronized void synchronize() {
41         while(true) {
42                 if(tickets>0) {
43                     try {
44                         Thread.sleep(30);
45                     } catch (InterruptedException e) {
46                         // TODO Auto-generated catch block
47                         e.printStackTrace();
48                     }
49                     System.out.println(Thread.currentThread().getName()+"窗口正在售卖第"+(tickets--)+"张票。。");
50                 }
51             
52         }
53         
54     }
55 }

    C:静态同步方法

       把同步加在方法上。

       这里的锁对象是当前类的字节码文件对象(反射)

 1 package com.wyh.Thread07_tickets2_同步方法静态;
 2 
 3 /** 
 4 * @author WYH
 5 * @version 2019年11月22日 下午7:42:37
 6 */
 7 public class SellTicket_Runnable2 implements Runnable {
 8     private static int tickets = 300;
 9     private int x = 0;
10     
11     
12 
13     @Override
14     public void run() {
15         if(x%2==0) {
16             while(true) {
17                 synchronized(SellTicket_Runnable2.class) {
18                     if(tickets>0) {
19                         try {
20                             Thread.sleep(30);
21                         } catch (InterruptedException e) {
22                             e.printStackTrace();
23                         }
24                         System.out.println(Thread.currentThread().getName()+"窗口正在售卖第"+(tickets--)+"张票。。");
25                     }
26                 }
27                 
28             }
29         }else {
30                 synchronize();
31         }
32         
33 
34     }
35 
36 
37     private synchronized static void synchronize() {
38         while(true) {
39                 if(tickets>0) {
40                     try {
41                         Thread.sleep(30);
42                     } catch (InterruptedException e) {
43                         e.printStackTrace();
44                     }
45                     System.out.println(Thread.currentThread().getName()+"窗口正在售卖第"+(tickets--)+"张票。。");
46                 }
47             
48         }
49         
50     }
51 }

·  (11)回顾以前的线程安全的类

      A:StringBuffer

      B:Vector

      C:HashTable

      D:如何把一个线程不安全的集合变成一个线程安全的集合类

          用Collections 工具类的方法即可。

以List集合为例:其他集合创建方法类似,具体看API

 1 package Collections保证线程安全的;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Collections;
 5 import java.util.List;
 6 
 7 /** 
 8 * @author WYH
 9 * @version 2019年11月22日 下午9:10:58
10 */
11 public class Demo {
12     public static void main(String[] args) {
13         //以List集合为例
14         //以前的我们是这么做的
15         List<String> list1 = new ArrayList<String>(); //这么创建的List是不安全的
16         
17         
18         
19         //Collections 工具类提供的方法 同步安全的
20         List<String> list2 = Collections.synchronizedList(new ArrayList<String>());
21         
22         list2.add("1");
23         list2.add("2");
24         
25         for(String s : list2) {
26             System.out.println(s);
27         }
28     }
29 
30 }

线程中需要注意的问题:

  1、Thread中start()方法的功能就是创建一个新的线程,并自动调用该线程的run()方法,直接调用run()方法是不会创建一个新的线程的,直接调用相当于调用一个普通方法。

  2、执行一个线程实际就是执行该线程run方法中的代码

  3、一个Thread对象只能代表一个线程。

      一个Thread对象不能调用两次start()方法,否则会抛出java.lang.IllegalThreadStateException异常

原文地址:https://www.cnblogs.com/wyh-study/p/11914742.html