您的位置:首页 > 编程语言 > Java开发

Java中Thread的使用、死锁以及生产者消费者问题详解

2015-01-27 14:56 573 查看
线程的创建主要有四种方式,一种是直接继承Thread实现,另一种是引用接口Runable。这两种创建的线程可以多次使用。也可以运用内部类实现接口的创建。但是用这种方法创建的线程只能用一次。以下就是线程的四种创建方式的相关代码:



1 package java819;
 2 
 3 public class TestThread {
 4         public static void main(String[] args) {
 5                 MyThread1 mt = new MyThread1();
 6                 MyThread2 mt2 = new MyThread2();
 7                 mt.start();
 8                 new Thread(mt2).start();
 9                 new Thread() {//内部类实现
10                         public void run() {
11                                 for (int i = 0; i < 100; i++) {
12                                         System.out.println("++++线程3++++++" + i);
13                                 }
14                         }
15                 }.start();
16                 new Thread(new Runnable() {
17                         
18                         @Override
19                         public void run() {
20                                 for (int i = 0; i < 100; i++) {
21                                         System.out.println("******线程4****" + i);
22                                 }
23                         }
24                 }).start();
25                 for (int i = 0; i < 100; i++) {
26                         System.out.println("******主线程****" + i);
27                 }
28         }
29 }
30 /**
31  * 
32  * 四种方法实现线程的创建,两种运用的是内部类 一种是实现接口,一种是继承线程
33  * 
34  */
35 class MyThread1 extends Thread {
36         @Override
37         public void run() {
38                 for (int i = 0; i < 100; i++) {
39                         System.out.println("++++线程一++++++" + i);
40                 }
41         }
42 }
43 class MyThread2 implements Runnable {
44         @Override
45         public void run() {
46                 for (int i = 0; i < 100; i++) {
47                         System.out.println("-----线程二-------" + i);
48                 }
49         }
50 }




当想让线程暂时暂停,进入休眠状态,可以用Sleep实现,该方法是静态方法,可以直接被Thread引用。可以在方法中设置休眠的时间。下面通过一个例子来说明Sleep的用法



1 package java819;
 2 import java.io.IOException;
 3 import java.nio.CharBuffer;
 4 public class TestSleep {
 5         public static void main(String[] args) {
 6                 Runner r = new Runner();
 7                 Thread t1 = new Thread(r);
 8                 Thread t2 = new Thread(r);
 9                 t1.start();
10                 t2.start();
11         }
12 }
13 class Runner implements Runnable {
14         @Override
15         public void run() {
16                 for (int i = 0; i < 200; i++) {
17                         if (i % 10 == 0 && i != 0) {
18                                 try {
19                                         Thread.sleep(1000); //Sleep的用法
20                                 } catch (InterruptedException e) {
21                                         e.printStackTrace();
22                                 }
23                         }
24                         System.out.println("——————————线程————————————" + i);
25                 }
26         }
27 }




当想让一个线程先执行完再去执行另一个线程时,可以用Join方法将当前线程先执行完。下面通过一个例子来说明Join的用法。



1 package cn.yj3g;
 2 public class TestJoin {
 3         public static void main(String[] args) {
 4                 MyThread2 t1 = new MyThread2("zhangcun");
 5                 t1.start();
 6                 try {
 7                     t1.join();//先执行调用join方法的线程对象的run方法,完成后才调用这条语句所在的线程
 8                 } catch (InterruptedException e) {
 9                         e.printStackTrace();
10                 }
11 
12                 for (int i = 1; i <= 10; i++) {
13                         System.out.println("------i am main thread");
14                 }
15         }
16 }
17 class MyThread2 extends Thread {  
18         MyThread2(String s) {
19                 super(s);
20         }
21         public void run() {
22                 for (int i = 1; i <= 10; i++) {
23                         System.out.println("I am " + getName());
24                         try {
25                                 sleep(1000);
26                         } catch (InterruptedException e) {
27                                 System.out.println("又被打爆了!");
28                                 return;
29                         }
30                 }
31         }
32 }




当需要一个线程让出当前执行状态即CPU,给其他线程执行的机会,就需要使用Yield方法,使当前线程暂时阻塞,让程序去执行其他的线程。还是通过一个例子来说明。



1 package java819;
 2 public class TestYield {
 3         public static void main(String[] args) {
 4                 MyYield my1 = new MyYield();
 5                 MyYield2 my2 = new MyYield2();
 6                 my1.start();
 7                 my2.start();
 8 
 9         }
10 }
11 class MyYield extends Thread {
12         @Override
13         public void run() {
14                 for (int i = 0; i < 100; i++) {
15                         System.out.println("数字为:" + i);
16                         if (i % 10 == 0 && i != 0) {
17                                 yield();
18                         }
19                 }
20         }
21 }
22 class MyYield2 extends Thread {
23         @Override
24         public void run() {
25                 for (int i = 0; i < 100; i++) {
26                         System.out.println("线程二数字为:" + i);
27                         if (i % 10 == 0 && i != 0) {
28                                 yield();
29                         }
30                 }
31         }
32 }




判断当前线程是否还在执行可以使用Thread.currentThread().isAlive()实现。

如果想让某一个线程的优先级优先,可以通过setPriority来设置线程的优先级。当然也会有一个getPriority来获取优先级MinPriority=1,MaxPriority=10,NomPriority=5。下面通过一个例子来说明setPriority的用法。



1 package java819;
 2 public class TestPriority {
 3         public static void main(String[] args) {
 4                 T1 t = new T1();
 5                 T2 tt = new T2();
 6                 tt.setPriority(Thread.NORM_PRIORITY + 4);//设置线程的优先级来改变线程的优先级
 7                 t.start();
 8                 tt.start();
 9         }
10 }
11 class T1 extends Thread {
12 
13         @Override
14         public void run() {
15                 for (int i = 0; i < 100; i++) {
16                         System.out.println("线程T1" + i);
17                 }
18         }
19 }
20 class T2 extends Thread {
21 
22         @Override
23         public void run() {
24                 for (int i = 0; i < 100; i++) {
25                         System.out.println("--------线程T2" + i);
26                 }
27         }
28 }




如果想实现当一个线程在占用一个资源时,不让别的线程来抢占资源,可以使用synchronized来修饰方法或者语句块,这样别的线程就不会进入synchronized修饰的方法或者方法块。

wait()和sleep()的区别:

<1>wait()时别的线程可以访问锁定对象。

<2>调用该方法时必须锁定该对象。

<3>sleep()时别的线程不可以访问锁定对象。

如果两个线程互相占用对方资源,那么线程将会进入死锁状态,在实现线程时,应该尽量避免死锁情况。下面就是一个典型的死锁例子,在编程时,我们应该要避免死锁的发生。

死锁例子:



1 package java819;
 2 public class TestDeadLock implements Runnable {
 3         public int flag = 1;
 4         static Object o1 = new Object(), o2 = new Object();
 5         @Override
 6         public void run() {
 7                 System.out.println("flag=" + flag);
 8                 if (flag == 1) {
 9                         synchronized (o1) {
10                                 try {
11                                         Thread.sleep(500);
12                                 } catch (Exception e) {
13                                         e.printStackTrace();
14                                 }
15                                 synchronized (o2) {
16                                         System.out.println("1");
17                                 }
18                         }
19                 }
20                 if (flag == 0) {
21                         synchronized (o2) {
22                                 try {
23                                         Thread.sleep(500);
24                                 } catch (Exception e) {
25                                         e.printStackTrace();
26                                 }
27                                 synchronized (o1) {
28                                         System.out.println("0");
29                                 }
30                         }
31                 }
32         }
33         public static void main(String[] args) {
34                 TestDeadLock td1 = new TestDeadLock();
35                 TestDeadLock td2 = new TestDeadLock();
36                 td1.flag = 1;
37                 td2.flag = 0;
38                 Thread t1 = new Thread(td1);
39                 Thread t2 = new Thread(td2);
40                 t1.start();
41                 t2.start();
42         }
43 }




通过以上所学的知识,我们就可以实现生活中常遇到的一个生产者消费者问题。下面我就通过一个实例来对这个问题进行下说明。

生产者消费者问题:



1 package cn.yj3g;
  2 public class TestPC {
  3         public static void main(String[] args) {
  4                 PizzaStack ps = new PizzaStack();
  5 
  6                 Thread t1 = new Thread(new Cooker(ps));
  7                 Thread t3 = new Thread(new Cooker(ps));
  8                 Thread t5 = new Thread(new Cooker(ps));
  9                 Thread t2 = new Thread(new Customer(ps));
 10                 Thread t4 = new Thread(new Customer(ps));
 11                 t1.start();
 12                 t3.start();
 13                 t2.start();
 14                 t4.start();
 15                 t5.start();
 16         }
 17 }
 18 /*
 19  * 厨子
 20  */
 21 class Cooker implements Runnable {
 22         PizzaStack ps;
 23         
 24         public Cooker(PizzaStack ps) {
 25                 this.ps = ps;
 26         }
 27 
 28         @Override
 29         public void run() {
 30                 ps.push();
 31         }    
 32 }
 33 /*
 34  * 食客
 35  */
 36 class Customer implements Runnable {
 37         PizzaStack ps;
 38         public Customer(PizzaStack ps) {
 39                 this.ps = ps;
 40         }
 41         @Override
 42         public void run() {
 43                  ps.pop();
 44         }
 45 }
 46 /*
 47  * pizza
 48  */
 49 class Pizza {
 50         int id;        
 51         public Pizza(int id) {
 52                 this.id = id;
 53         }        
 54         public String toString() {
 55                 return "pizza "+id;
 56         }
 57 }
 58 /*
 59  * pizza筐
 60  */
 61 class PizzaStack {       //栈
 62         private Pizza[] ps = new Pizza[10];
 63         int size;     
 64         public void push() {              
 65                 while(size>=0 && size<ps.length) {
 66                         synchronized (this) {//此语句块锁住
 67                                 this.notifyAll();//唤醒所有线程
 68                                 Pizza p = new Pizza(size);
 69                                 ps[size++] = p;
 70                                 System.out.println("+++++++生产了"+p+" 剩下"+size+"个");
 71                         }
 72                         try {
 73                                 Thread.sleep((long)(Math.random()*1000));
 74                         } catch (InterruptedException e) {
 75                                 e.printStackTrace();
 76                         }
 77                 } 
 78                 try {
 79                         synchronized (this) {
 80                                 wait();
 81                         }
 82                 } catch (InterruptedException e) {
 83 
 84                 }
 85                 push();
 86         }     
 87         public void pop() {
 88                 while(size>0 && size<=ps.length) {
 89                         synchronized(this) {
 90                                 this.notifyAll();
 91                                 Pizza p = ps[--size];
 92                                 System.out.println("------消费了"+p+" 剩下"+size+"个");
 93                         }
 94                         try {
 95                                 Thread.sleep((long)(Math.random()*1000));
 96                         } catch (InterruptedException e) {
 97                                 e.printStackTrace();
 98                         }
 99                 } 
100                 try {
101                         synchronized (this) {
102                                 wait();
103                         }
104                 } catch (InterruptedException e) {
105                 }
106                 pop();
107         }     
108 }




以上就是有关线程的全部内容,在以后的编程中我们会经常用到线程,所以这方面的知识要牢牢掌握。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐