黑马程序员系列第二篇 多线程(2)

时间:2023-02-19 14:01:06

 ASP.Net+Android+IOS开发  、Net培训、期待与您交流!

 

(前言:本篇文章主要依据毕向东老师的课程视频整理而成,如要详细学习,请观看毕老师视频  百度网盘链接地址:http://pan.baidu.com/s/1i3m6DrJ)

 

目录:1、线程通信--生产消费者示例(线程通信安全、等待唤醒机制)    2、停止线程、及其会出现的问题、及解决的办法    3、守护线程及几个Thread的方法                   4、工作中线程的常见写法

1、线程通信--生产消费者示例

代码示例:

public class ProducerConsumer {
//需求:生产和消费行为依次进行。 设置产品为BMW 设置生产者和消费者线程各两个
public static void main(String[] args) {

Product pro
=new Product();

new Thread(new Producter(pro)).start();
new Thread(new Consumer(pro)).start();
new Thread(new Producter(pro)).start();
new Thread(new Consumer(pro)).start();

}
}
class Product{

private String name;
private int No=1;
boolean flag=false;

public synchronized void set(String names){
while(flag)
try {
this.wait();//等待状态
} catch (InterruptedException e) {
e.printStackTrace();
}
this.name=names+"---"+this.No++;
System.out.println(
this.name+"---被"+Thread.currentThread().getName()+"生产");
flag
=true;
this.notifyAll();//唤醒所有线程
}
public synchronized void out(){
while(!flag)
try {
this.wait();//等待状态
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(
this.name+"---被"+Thread.currentThread().getName()+"消费了-------");
flag
=false;
this.notifyAll();//唤醒所有线程
}
}
//生产者
class Producter implements Runnable{
private Product p;
public Producter(Product pr){
this.p=pr;
}
public void run(){
while(true){
p.set(
"BMW");
}
}
}
//消费者
class Consumer implements Runnable{
private Product p;
public Consumer(Product pr){
this.p=pr;
}
public void run(){
while(true){
p.out();
}
}
}

 

 

 

使用JDK5.0新特性改进后的代码

 1 /*JDK5.0后增加了Lock 和Condition新类特性来取代 同步和锁的繁琐操作 */
2 public class ProducerConsumerNew {
3
4 public static void main(String[] args) {
5
6 Product pro=new Product();
7
8 new Thread(new Producter(pro)).start();
9 new Thread(new Consumer(pro)).start();
10 new Thread(new Producter(pro)).start();
11 new Thread(new Consumer(pro)).start();
12
13 }
14
15 }
16 class ProductNew{
17 private String name;
18 private int No=1;
19 boolean flag=false;
20
21 private Lock lock=new ReentrantLock();
22 private Condition con1=lock.newCondition();
23 private Condition con2=lock.newCondition();
24
25 public void set(String name){
26
27 while(flag)
28 try {
29 lock.lock();
30 con1.wait();
31 } catch (InterruptedException e) {
32 e.printStackTrace();
33 }finally{
34 lock.unlock();
35 }
36 this.name=name+"---"+this.No++;
37 System.out.println(this.name+"---被"+Thread.currentThread().getName()+"生产");
38
39 this.flag=true;
40 con2.signal();
41 }
42
43 public void out(){
44 while(!this.flag)
45 try {
46 lock.lock();
47 con2.wait();
48 } catch (InterruptedException e) {
49 e.printStackTrace();
50 }finally{
51 lock.unlock();
52 con1.signal();
53 }
54 System.out.println(this.name+"---被"+Thread.currentThread().getName()+"消费了-------");
55
56 this.flag=false;
57 }
58 }
59 //生产者
60 class ProducterNew implements Runnable{
61 private ProductNew p;
62 public ProducterNew(ProductNew pr){
63 this.p=pr;
64 }
65 public void run(){
66 while(true){
67 p.set("BMW");
68 }
69 }
70 }
71 //消费者
72 class ConsumerNew implements Runnable{
73 private ProductNew p;
74 public ConsumerNew(ProductNew pr){
75 this.p=pr;
76 }
77 public void run(){
78 while(true)
79 p.out();
80 }
81 }

 

 

  

2、停止线程、及其会出现的问题、及解决的办法    

停止线程思路:开启多线程运行,运行代码通常是循环结构,只要控制住循环,就可以让run()方法结束,线程即结束。

特殊情况:当线程处于冻结状态(wait()),就不会读取到标记,那么线程就不会结束。

解决办法:当没有指定的方式让冻结的线程恢复到运行状态时,需要用Interrupt()方法强制清除冻结状态,再用操作标记让线程结束 

 

一个简单的代码例子

 1 public class ThreadStop {
2
3 public static void main(String[] args) {
4
5 ThreadTt tt=new ThreadTt();
6
7 Thread th1=new Thread(tt);
8 Thread th2=new Thread(tt);
9 th1.start();
10 th2.start();
11 int count=0;
12 while(true){
13 if(++count>60){ //循环来控制线程的结束
14 th1.interrupt(); //强制清除线程冻结状态
15 th2.interrupt();
16 break;
17 }
18 System.out.println(Thread.currentThread().getName()+"....run---"+count);
19 }
20 System.out.println(Thread.currentThread().getName()+"....over");
21 }
22 }
23 class ThreadTt implements Runnable{
24
25 boolean flag=true;
26 Lock lock=new ReentrantLock();
27 Condition con=lock.newCondition();
28 public synchronized void run() {
29
30 while(flag){
31 try {
32 wait(); //用这个方法让线程处于冻结状态
33 } catch (InterruptedException e) {
34 System.out.println(e.getStackTrace());
35 flag=false;
36 }
37 System.out.println(Thread.currentThread().getName()+"...run");
38 }
39 }
40 }

 

 

 

 

3、守护线程及几个Thread的方法

 

守护线程/用户线程:通俗而言为”后台进程”,当前台进程都结束时,后台进程自动结束;当正在运行的线程都是守护线程时,JVM自动退出。     

 

setDaemon()方法设置守护线程,该方法必须在启动线程前调用

 

 

Join()方法  特点:当A线程执行到了B线程的jion()方法是,A就会等待,等B线程都执行完以后,A才会执行。Jion可以用来临时加入线程执行    线程抢夺cpu执行权

 

ToString()方法

 

setPriority()方法 更改线程的优先级,优先级代表抢夺资源的频率高低

 

Yield()方法  暂停当前线程的执行,去执行其它线程

 

4、工作中线程的常见写法(用到内部类)

不多说,看代码

 

 1 public class ThreadStand {
2
3 public static void main(String[] args) {
4 //工作中多线程的常见写法,构建内部类
5 new Thread(){
6 public void run(){
7 for(int i=0;i<100;i++)
8 System.out.println(Thread.currentThread().getName()+"....run...."+i);
9 }
10 }.start();
11
12 for(int i=0;i<100;i++)
13 System.out.println(Thread.currentThread().getName()+"....run...."+i);
14
15 //构造内部类
16 Runnable rn= new Runnable(){
17 public void run() {
18 for(int i=0;i<100;i++)
19 System.out.println(Thread.currentThread().getName()+"....run...."+i);
20 }
21 };
22 new Thread(rn).start();
23 }
24 }

 

 

 

 

       

       初学者难免错误,欢迎评判指教,持续更正ing...........

 

ASP.Net+Android+IOS开发  、Net培训、期待与您交流!