黑马程序员---java基础-Java 多线程

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

进程指的是一个正在执行中的程序,而线程则是进程中一个负责程序执行的控制单元。一个进程中可以有多个执行路径,这就是多线程。开启多个线程可以运行多部分代码,这样就能运行多个功能

一、多线程的创建

在java中,创建多线程主要有以下两个方式:

1、继承Thread类:

 1 public class test {
 2
 3   public static void main(String[] args) {
 4
 5       //创建对象
 6
 7       ProducerProject p1=new ProducerProject();
 8
 9       p1.setName("生产者1");
10
11       ProducerProject p2=new ProducerProject();
12
13       p2.setName("生产者2");
14
15       //开始执行线程
16
17       p1.start();
18
19       p2.start();
20
21   }
22
23 }
24
25 //继承Thread类
26
27 class ProducerProject extends Thread{
28
29   //覆盖Thread类中 的run()方法
30
31   public void run(){
32
33       for(int i=0;i<5;i++){
34
35           System.out.println(Thread.currentThread().getName()+"..生产商品"+i);
36
37       }
38
39   }
40
41 }

2、实现Runnable接口

 1 public class test2{
 2     public static void main(String[] args){
 3         //创建ProducerProject2对象
 4         ProducerProject2 p=new ProducerProject2();
 5         //将p作为参数构造Thread对象,创建线程
 6         Thread t1=new Thread(p);
 7         Thread t2=new Thread(p);
 8
 9         t1.setName("生产者1");
10         t2.setName("生产者1");
11         //启动线程
12         t1.start();
13         t2.start();
14     }
15 }
16
17 //实现Runnable接口
18 class ProducerProject2 implements Runnable{
19     //实现run()方法
20     public void run() {
21         for(int i=0;i<5;i++){
22             System.out.println(Thread.currentThread().getName()+"..生产商品"+i);
23         }
24     }
25 }

实现Runnable接口避免了单继承的局限性,并且可以实现资源的共享,适合多个相同的程序代码的线程去处理同一资源,所以一般建议使用第二种线程创建方式。我们可以用静态方法currentThread()来获取当前线程对象,getName()和setName()可以用来获取和设置线程名称。

二、synchronized 锁和wait、notify、notifyAll 的应用

 1 /*
 2  * 线程间通信
 3  * 其实是多个线程在操作同一个资源
 4  * 但是操作的动作不同
 5  *
 6  * 等待 唤醒机制
 7  *
 8  * wait()
 9  * nitify()
10  * notifyAll()
11  * 都使用在同步中。
12  * 因为要对持有监视器(锁)的线程操作
13  * 所以要使用在同步中,只有同步才具有锁
14  * 为什么这些操作要定义在Object类中
15  * 因为这些方法在操作同步线程中,都必须
16  * 标示他们所操作线程中的锁
17  * 只有同一个锁上的被等待线程,
18  * 可以被同一个锁上的notify 唤醒
19  * 不可以对不同锁上的线程进行唤醒
20  *
21  * 也就是说,等待唤醒的线程必须是同一个锁上
22  * 而锁可以是任意对象,所以可以被任意对象调用的方法定义在
23  * Object类
24  *
25  * */
26 class Res{
27     String name;
28     String sex;
29     boolean rw=false;
30 }
31 class Input implements Runnable{
32     Res res;
33     public Input(Res res) {
34         this.res=res;
35     }
36     public void run() {
37         boolean flag=true;
38         while (true) {
39             synchronized (res) {
40                 if(res.rw)
41                     try {
42                         res.wait();
43                     } catch (InterruptedException e) {
44                         e.printStackTrace();
45                     }
46                 if (flag) {
47                     res.name="mike";
48                     res.sex="man";
49                 }else {
50                     res.name="丽丽";
51                     res.sex="女";
52                 }
53                 flag=flag==true?false:true;
54                 res.rw=true;
55                 res.notify();
56             }
57         }
58     }
59 }
60 class Output implements Runnable{
61     Res res;
62     public Output(Res res) {
63         this.res=res;
64     }
65     public void run() {
66         while (true) {
67             synchronized (res) {
68                 if(!res.rw)
69                     try {
70                         res.wait();
71                     } catch (InterruptedException e) {
72                         e.printStackTrace();
73                     }
74                 System.out.println(res.name+"-"+res.sex);
75                 res.rw=false;
76                 res.notify();
77             }
78         }
79     }
80 }
81 public class InputOutputDemo {
82     public static void main(String[] args) {
83         Res res=new Res();
84         Input input=new  Input(res);
85         Output output=new Output(res);
86         Thread threadIn=new Thread(input);
87         Thread threadOut=new Thread(output);
88         threadIn.start();
89         threadOut.start();
90     }
91
92 }

-----------可以对代码进行优化,得到以下代码

 1 /*
 2  * 线程间通信
 3  * 其实是多个线程在操作同一个资源
 4  * 但是操作的动作不同
 5  *
 6  * 等待 唤醒机制
 7  *
 8  * wait()
 9  * nitify()
10  * notifyAll()
11  * 都使用在同步中。
12  * 因为要对持有监视器(锁)的线程操作
13  * 所以要使用在同步中,只有同步才具有锁
14  * 为什么这些操作要定义在Object类中
15  * 因为这些方法在操作同步线程中,都必须
16  * 标示他们所操作线程中的锁
17  * 只有同一个锁上的被等待线程,
18  * 可以被同一个锁上的notify 唤醒
19  * 不可以对不同锁上的线程进行唤醒
20  *
21  * 也就是说,等待唤醒的线程必须是同一个锁上
22  * 而锁可以是任意对象,所以可以被任意对象调用的方法定义在
23  * Object类中
24  *
25  * ------------------------------代码优化-----------------------------------
26  * */
27 class Res2{
28     private String name;
29     private String sex;
30     private boolean rw=false;
31     public synchronized void setNameSex(String name,String sex) {
32         if (rw) {
33             try {
34                 this.wait();
35             } catch (InterruptedException e) {
36                 e.printStackTrace();
37             }
38         }
39         this.name = name;
40         this.sex = sex;
41         rw=true;
42         this.notify();
43     }
44     public synchronized void getSexName() {
45         if (!rw) {
46             try {
47                 this.wait();
48             } catch (InterruptedException e) {
49                 e.printStackTrace();
50             }
51         }
52         System.out.println(name+"---"+sex);
53         rw=false;
54         this.notify();
55     }
56 }
57 class Input2 implements Runnable{
58     Res2 res;
59     public Input2(Res2 res) {
60         this.res=res;
61     }
62     public void run() {
63         boolean flag=true;
64         while (true) {
65
66                 if (flag) {
67                     res.setNameSex("mike","man");
68                 }else {
69                     res.setNameSex("丽丽","女");
70                 }
71                 flag=flag==true?false:true;
72             }
73         }
74 }
75 class Output2 implements Runnable{
76     Res2 res;
77     public Output2(Res2 res) {
78         this.res=res;
79     }
80     public void run() {
81         while (true) {
82                 res.getSexName();
83             }
84         }
85 }
86 public class InputOutputDemo2 {
87     public static void main(String[] args) {
88         Res2 res=new Res2();
89 //        Input2 input=new  Input2(res);
90 //        Output2 output=new Output2(res);
91 //        Thread threadIn=new Thread(input);
92 //        Thread threadOut=new Thread(output);
93 //        threadIn.start();
94 //        threadOut.start();
95         new Thread(new  Input2(res)).start();
96         new Thread(new Output2(res)).start();
97
98     }
99 }

三、用Lock 代替synchronized 实现线程同步

  1 import java.util.concurrent.locks.Condition;
  2 import java.util.concurrent.locks.Lock;
  3 import java.util.concurrent.locks.ReentrantLock;
  4
  5 /*对于多个生产者和消费者
  6  * 为什么要定义while 判断标记
  7  * 原因:为了让被唤醒的线程再一次判断标记
  8  *
  9  * 为什么定义notifyAll()
 10  * 因为需要唤醒对方线程
 11  * 因为只用notify ,容易出现只唤醒本方线程的情况,导致程序中的所有线程都等待
 12  *
 13  *
 14  * jdk 1.5 中国提供了多线程升级解决方案
 15  * 将同步 的synchronized替换成Lock操作
 16  * 将 Object 中的 wait  notify   notifyAll 替换了Condition  对象
 17  * 该对象可以Lock锁进行获取
 18  * 在该例子中,实现了本方只唤醒对方线程操作
 19  * */
 20 public class ProduceConsumeLockDemo {
 21
 22     public static void main(String[] args) {
 23         Resource2 resource=new Resource2();
 24         Produce2 produce=new Produce2(resource);
 25         Consume2 consume=new Consume2(resource);
 26
 27         Thread threadPro1=new Thread(produce);
 28         Thread threadPro2=new Thread(produce);
 29         Thread threadConsume2e1=new Thread(consume);
 30         Thread threadConsume2e2=new Thread(consume);
 31         threadPro1.start();
 32         threadPro2.start();
 33         threadConsume2e1.start();
 34         threadConsume2e2.start();
 35     }
 36
 37 }
 38 class Produce2 implements Runnable{
 39     private Resource2 resource;
 40     public Produce2(Resource2 resource) {
 41         this.resource=resource;
 42     }
 43     public  void run() {
 44         while (true) {
 45             try {
 46                 resource.set("+商品+");
 47             } catch (InterruptedException e) {
 48                 e.printStackTrace();
 49             }
 50         }
 51     }
 52 }
 53 class Consume2 implements Runnable{
 54     private Resource2 resource;
 55     public Consume2(Resource2 resource) {
 56         this.resource=resource;
 57     }
 58     public  void run() {
 59         while (true) {
 60             try {
 61                 resource.out();
 62             } catch (InterruptedException e) {
 63                 e.printStackTrace();
 64             }
 65         }
 66     }
 67
 68 }
 69 class Resource2{
 70     private String name;
 71     private int count =1;
 72     private boolean flag=false;
 73     //---------------------------------------------------------
 74     private Lock lock =new ReentrantLock();
 75     private Condition con_Produce=lock.newCondition();
 76     private Condition con_Consume=lock.newCondition();
 77     //---------------------------------------------------------
 78     public  void set (String name)throws InterruptedException {
 79         lock.lock();//-----------------------
 80             try {
 81                 while(flag){
 82 //                    con.await();
 83                     con_Produce.await();
 84                 }
 85                 this.name=name+"--"+count++;
 86                 System.out.println(Thread.currentThread().getName()+"--生产者--"+this.name);
 87                 flag=true;
 88 //                con.signal();
 89 //                con.signalAll();//还是唤醒了所有线程
 90                 con_Consume.signal();
 91             }finally{
 92                 lock.unlock();//--------------
 93                 //释放锁的动作一定要执行
 94             }
 95     }
 96     public  void out() throws InterruptedException{
 97         lock.lock();//进来,先拿到锁
 98         try {
 99             while(!flag){
100                 con_Consume.await();
101             }
102             System.out.println(Thread.currentThread().getName()+"----消费者-----"
103 + this.name);
104             flag=false;
105 //con.signal();
106             con_Produce.signal();
107         }finally{
108             lock.unlock();
109         }
110
111     }
112 }

四、Thread的stop()方法和interrup()方法

 1 /*
 2  * stop 方法以及过时
 3  * 如何停止线程
 4  * 只有一种方法 run 方法 运行结束
 5  *
 6  * 开启多线程运行,运行代码通常是循环结构
 7  * 只要控制住循环,就可以让run方法结束,也就是线程结束
 8  *
 9  * 特殊情况
10  * 当线程处于冻结状态,就不会读到标记
11  * 那么线程就不会结束
12  *
13  * interrupt 强制将冻结状态的线程 运行起来
14  * 当没有指定的方式让冻结的线程回复都爱运行状态时
15  *
16  * 这时需要对冻结状态进行清除
17  * 强制让线程恢复到运行状态中来,就可以操作标记你,让线程结束
18  * Thread类 interrupt 提供了该功能
19  *
20  * 守护线程 或者 用户线程
21  *
22  * 标记为后台线程  :
23  * 处理结束和普通线程有区别外,其他都一样
24  * 当所有前台线程都结束后,后台线程自动结束(有依赖的意思)
25  * 主线程是前台线程。
26  * 当正在运行的线程都是守护线程是。jvm自动停止
27  * */
28 public class StopThreadDemo {
29     public static void main(String[] args) {
30         StopThread st=new StopThread();
31         Thread t1=new Thread(st);
32         Thread t2=new Thread(st);
33         t1.setDaemon(true);
34         t2.setDaemon(true);
35         t1.start();
36         t2.start();
37
38         int num=0;
39         while (true) {
40             if (num++==60) {
41 //                st.changFlag();
42 //                t1.interrupt();
43 //                t2.interrupt();
44                 break;
45             }
46             System.out.println(Thread.currentThread().getName()+"main -"+num);
47         }
48         System.out.println("over");
49     }
50 }
51 class StopThread implements Runnable{
52     private boolean flag=true;
53     public synchronized void run() {
54         while(flag){
55             try {
56                 wait();
57             } catch (InterruptedException e) {
58 //                e.printStackTrace();
59                 System.out.println(Thread.currentThread().getName()+"----InterruptedException");
60                 flag=false;
61             }
62             System.out.println(Thread.currentThread().getName()+"----run");
63         }
64     }
65     public void changFlag(){
66         flag=false;
67     }
68 }

五、Thread的join()方法

 1 /*
 2  * 当 A线程执行到了 B线程的Join方法时
 3  * A线程就会等待B线程终止,A才会 执行
 4  * join可以用来临时加入线程执行
 5  *
 6  * Thread[Thread-0,5,main]--- run29
 7 Thread[Thread-1,5,main]--- run32
 8 Thread[Thread-0,5,main]--- run30
 9 Thread【线程名,优先级,线程组】 一般谁开启了线程,线程属于哪个组
10 优先级 代表 使用cpu 的使用频率
11 默认优先级是  5
12 优先级 分 1 ----10 级
13 static int MAX_PRIORITY     10
14           线程可以具有的最高优先级。
15 static int MIN_PRIORITY     1
16           线程可以具有的最低优先级。
17 static int NORM_PRIORITY    5
18           分配给线程的默认优先级。
19
20  * */
21 public class ClassJoinDemo  {
22     public static void main(String[] args) throws Exception {
23         JoinDmeo joinDmeo=new JoinDmeo();
24         Thread thread1=new Thread(joinDmeo);
25         Thread thread2=new Thread(joinDmeo);
26
27         thread1.start();
28 //        thread1.setPriority(Thread.MAX_PRIORITY);
29
30 //        thread1.join();
31         /*thread1.join();
32          * thread1 请求执行权
33          * 主线程处于冻结状态
34          * thread1 结束后 主线程才恢复到运行状态
35          * 等待这个线程 终止
36          * 当进行多线程运行时,
37          * 临时加入一个线程,让这个线程运算完,
38          * */
39         thread2.start();
40 //        thread1.join();
41         for (int i = 0; i < 80; i++) {
42             System.out.println("mian "+i);
43         }
44         System.out.println("mina over");
45     }
46
47 }
48 class JoinDmeo implements Runnable{
49     public void run() {
50         for (int i = 0; i < 70; i++) {
51             System.out.println(Thread.currentThread().toString()+"--- run"+i);
52             Thread.yield();//  释放执行权
53         }
54     }
55
56 }
时间: 2024-12-17 22:24:04

黑马程序员---java基础-Java 多线程的相关文章

黑马程序员_Java基础:多线程总结

------- android培训.java培训.期待与您交流! ---------- 一.多线程的概念 进程和线程经常会被人混淆,那是因为对它们的概念不明确.就拿我们平时使用的操作系统来说,它是多任务的操作系统,而多线程就是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程.  线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如平时下载的软件迅雷进程中可以

黑马程序员 &nbsp; 两道java面试题

1.List,Set,Map是否都继承了Collection接口?  List,Map比较常用:List是通过下标来访问元素,Map是通过键值进行访问元素.应该不会同时都实现了Collection接口.  Collection是一个什么概念?还有Set在java中是怎样定义的?他是通过下标来访问元素还是通过键值来访问元素?两者谁继承了Collection接口呢?或者有没有可能两者都继承了Collection接口?时间不多了,我是这样写的:  Set,Map实现了Collection接口.而Lis

黑马程序员 【】java学习之路——TCP(三)客户端上传文件到服务器

------- <a href="http://www.itheima.com" target="blank">android培训</a>.<a href="http://www.itheima.com" target="blank">java培训</a>.期待与您交流! ---------- import java.io.*; import java.net.*; class

黑马程序员_Java异常 Java常用库类

Java异常 1,异常的基本概念 异常是导致程序中断运行的一种指令流,它是在运行时期发生的不正常的情况,在Java中,一切的异常都秉着面向对象的设计思想,所有的异常都是以对象和类的形式存在的. 2,异常类的继承结构 在整个Java的异常结构中,实际上有两个最常用的类,Exception和Error,这两个类分别是Throwable的子类 Exception:一般表示的是程序中出现的问题,可以直接使用try....catch处理 Error:一般之的是JVM的错误,程序中无法处理. 3,Java的

黑马程序员_JAVA 基础加强学习笔记

一.面向对象 (一)继承  1.继承的好处: (1) 提高了代码的复用性. (2) 让类与类之间产生了关系,提供了另一个特征多态的前提. 注意: 子类中所有的构造函数都会默认访问父类中的空参数的构造函数,因为每一个子类构造内第一行都有默认的语句super();  如果父类中没有空参数的构造函数,那么子类的构造函数内,必须通过super语句指定要访问的父类中的构造函数. 如果子类构造函数中用this来指定调用子类自己的构造函数,那么被调用的构造函数也一样会访问父类中的构造函数. 2.final特点

黑马程序员_Java基础加强(下)

8.注解类 注解相当于一种标记,加了注解就等于打上了某种标记,没加就等于没打特殊标记,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记就去干什么事,标记可以加在包.类.字段.方法,方法的参数以及局部变量上. 注解的应用结构图: 为注解增加属性 定义基本类型的属性和应用属性 在注解类中增加String color(); @MyAnnotation(color = "red") 用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法 MyAnno

黑马程序员_Java基础加强(上)

1.静态导入 静态导入是jdk1.5版本以后出现的新特性,一般是指导入静态方法,如:import static java.lang.System.out 是指导入系统输出的静态方法. 例: import static java.lang.System.out //导入java.lang包下的System类的静态方法out public class StaticImport { public static void main(String[] args) { int x=1; x++; out.p

黑马程序员-正则表达式基础

正则表达式是一种描述字符串集的方法,它是以字符串集中各字符串的共有特征为依据的.正则表达式可以用于搜索.编辑或者是操作文本和数据.它超出了 Java 程序设计语言的标准语法,因此有必要去学习特定的语法来构建正则表达式.正则表达式的变化是复杂的,一旦你理解了它们是如何被构造的话,你就能解析或者构建任意的正则表达式了..正则表达式由一些普通字符和一些元字符组成. 普通字符包括大小写的字母和数字,而元字符则具有特殊的含义.在最简单的情况下,一个正则表达式看上去就是一个普通的查找串.例如,正则表达式"a

黑马程序员_Java基础_接口

------- android培训.java培训.期待与您交流! ---------- 0.接口知识体系 Java接口的知识体系如下图所示,掌握下图中的所有知识就可精通接口. 1.接口概论 1)接口概念 接口是从多个相似类中抽象出来的规范,接口中不包含普通方法,所有方法都是抽象方法,接口不提供实现.接口体现的是规范和实现分离的哲学.规范和实现分离正是接口的好处,让软件系统的各个组件之间面向接口耦合,是一种松耦合的设计.接口定义的是多个类共同的公共行为规范,定义的是一组公用方法. 2)接口与抽象类

黑马程序员——集合基础知识(Map)

Map概念 要同时存储两个元素,他们之间有映射关系,每个键不能重复,每个键只能映射到一个值. 存储键值对,并且键是唯一的. 1.添加. put()如果添加的键原来有值,后添加的值会覆盖前面的值,并返回之前的值. 2.删除 remove()按键删除. 3.判断 4.获取 get(object key) size() value()拿值value返回的是值的集合... HashTable 底层是哈西数据结构,不可以存入null键null值,线程同步. HashMap 底层是哈西表数据结构,允许使用n