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

来源:互联网 发布:富特文格勒 知乎 编辑:程序博客网 时间:2024/06/05 20:48

线程的创建主要有四种方式,一种是直接继承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                         @Override19                         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         @Override37         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         @Override45         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         @Override15         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         @Override13         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         @Override24         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         @Override14         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         @Override23         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 }
复制代码

以上就是有关线程的全部内容,在以后的编程中我们会经常用到线程,所以这方面的知识要牢牢掌握。


0 0
原创粉丝点击