java-线程
线程:是一个程序里面不同的执行路径
进程:一个class文件,一个exe文件,静态的概念,进程的执行指的是进程里面的主线程,main方法执行了,实际上都是线程在执行
同一个时间点上,一个cpu只能支持一个线程在执行
两种方式创建线程:1.继承thread(只能是单继承较狭隘)
2.实现runnerable
一些常用到的方法属性:
sleep:休眠(并不释放锁)
join:合并线程(相当于方法调用)
yield:让出小会儿给别人执行
线程的优先级
Object.wait():(让正在访问此代码块的线程等待一下,让别的线程继续运行)调用此方法时,必须锁定该对象
Object.notify():(叫醒正在访问此代码块的单个线程)
Object.notifyAll():(叫醒正在访问此代码块的所有线程)
synchronized:线程同步(锁定当前内容,同一时间只有一个线程访问它):
死锁: 是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生 了死锁,这些永远在互相等待的进程称为死锁进程。 由于资源占用是互斥的,当某个进程提出申请资源后,使得有关进程在无外力协助下,永远分配不到必需的资源而无法继续运行,这就产生了一种特殊现象死锁
如果线程A锁住了记录1并等待记录2,而线程B锁住了记录2并等待记录1,这样两个线程就发生了死锁现象
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
package thread; /** * * @description * 死锁的例子 * @package name * thread.DeadLock.java * @author * lj * @since * 2012-4-8下午10:44:04 */ public class DeadLock implements Runnable{ int flag; static Object o1 = new Object();//注意是静态的,那样才是属于类独有的,不是属于对象的 static Object o2 = new Object(); public void run() { System.out.println("flag:" + flag); if(flag == 1) { synchronized (o1) { try{ Thread.sleep(500); }catch(Exception e){ e.printStackTrace(); } synchronized (o2) { System.out.println(" 看到了此输出说明flag为1的线程完全执行了"); } } }else{ synchronized (o2) { try{ Thread.sleep(500); }catch(Exception e){ e.printStackTrace(); } synchronized (o1) { System.out.println(" 看到了此输出说明flag为2的线程完全执行了"); } } } } public static void main(String[] args) { DeadLock dl1 = new DeadLock(); dl1.flag = 1; DeadLock dl2 = new DeadLock(); dl2.flag = 2; Thread t1 = new Thread(dl1); t1.start(); Thread t2 = new Thread(dl2); t2.start(); } }
System.out.println(" 看到了此输出说明flag为1/2的线程完全执行了"); 始终没有执行,没有输出,出现了死锁
生产者消费者问题:
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 package thread; 2 3 /** 4 * 5 * @description 6 * 生产者消费者问题 7 * @package name 8 * thread.ProducerConsumer.java 9 * @author 10 * lj 11 * @since 12 * 2012-4-8下午09:52:23 13 */ 14 public class ProducerConsumer { 15 public static void main(String[] args) { 16 Basket bk = new Basket(); 17 Producer p = new Producer(bk); 18 Consumer c = new Consumer(bk); 19 new Thread(p).start(); 20 new Thread(c).start(); 21 } 22 } 23 /** 24 * 25 * @description 26 * 馒头 27 * @package name 28 * thread.ProducerConsumer.java 29 * @author 30 * lj 31 * @since 32 * 2012-4-8下午09:52:46 33 */ 34 class Bun { 35 int id; 36 public Bun(int id) { 37 this.id = id; 38 } 39 40 public String toString() { 41 return "第" + (id+1) + "个馒头"; 42 } 43 } 44 /** 45 * 46 * @description 47 * 篓子 48 * @package name 49 * thread.ProducerConsumer.java 50 * @author 51 * lj 52 * @since 53 * 2012-4-8下午09:53:00 54 */ 55 class Basket { 56 Bun[] buns = new Bun[5]; 57 int index; 58 /** 59 * 生产馒头 60 * @author 61 * lj 62 * @since 63 * 2012-4-8下午09:54:28 64 * @param b void 65 * 返回 66 */ 67 public synchronized void add(Bun b) {//同步是防止生产者放了馒头,但是因为某些异常,index没有来得及加加,但是实际上框子的馒头个数可能超过了10,你还想放 68 while(index == buns.length) { 69 try { 70 this.wait(); 71 } catch (InterruptedException e) { 72 // TODO Auto-generated catch block 73 e.printStackTrace(); 74 System.out.println("生产馒头时候的等待异常"); 75 } 76 } 77 this.notify();//不写表明已经是满的了,但不叫醒消费者,就放在那里 78 buns[index] = b; 79 index++; 80 } 81 /** 82 * 消费馒头 83 * @author 84 * lj 85 * @since 86 * 2012-4-8下午09:54:50 87 * @return Bun 88 * 返回 89 */ 90 public synchronized Bun get() {//同步是防止消费者拿了馒头,但是因为某些异常,indent没有来得及减减,但是实际上框子里可能没有馒头了,但是你还想拿 91 while(index == 0) { 92 try { 93 this.wait(); 94 } catch (InterruptedException e) { 95 // TODO Auto-generated catch block 96 e.printStackTrace(); 97 System.out.println("拿馒头时候的等待异常"); 98 } 99 } 100 //用if出现了异常,程序会跳出if继续执行后面的语句,而while不会 101 /*if(index == 0) { 102 try { 103 this.wait(); 104 } catch (InterruptedException e) { 105 // TODO Auto-generated catch block 106 e.printStackTrace(); 107 } 108 }*/ 109 this.notify();//假设index=6,不写表明已经拿完了,但不叫醒生产者,总是空着 110 index--;//前面的index指针已经加加了,但是我没有那个位置装馒头,所以取出馒头的索引得往下减(类比栈内存) 111 return buns[index]; 112 } 113 } 114 /** 115 * 116 * @description 117 * 生产者 118 * @package name 119 * thread.ProducerConsumer.java 120 * @author 121 * lj 122 * @since 123 * 2012-4-8下午09:53:16 124 */ 125 class Producer implements Runnable{ 126 Basket bk; 127 public Producer(Basket bk) { 128 this.bk = bk; 129 } 130 @Override 131 public void run() { 132 for(int i = 0; i < 10; i++) { 133 Bun b = new Bun(i); 134 bk.add(b); 135 System.out.println("生产了" + b); 136 try { 137 Thread.sleep((int)Math.random()*1000); 138 } catch (InterruptedException e) { 139 // TODO Auto-generated catch block 140 e.printStackTrace(); 141 System.out.println("生产异常"); 142 } 143 } 144 } 145 146 } 147 /** 148 * 149 * @description 150 * 消费者 151 * @package name 152 * thread.ProducerConsumer.java 153 * @author 154 * lj 155 * @since 156 * 2012-4-8下午09:53:40 157 */ 158 class Consumer implements Runnable { 159 Basket bk; 160 public Consumer(Basket bk) { 161 this.bk = bk; 162 } 163 @Override 164 public void run() { 165 for(int i = 0; i < 10; i++) { 166 Bun b = bk.get(); 167 try { 168 Thread.sleep((int)Math.random()*1000); 169 } catch (InterruptedException e) { 170 // TODO Auto-generated catch block 171 e.printStackTrace(); 172 System.out.println("消费异常"); 173 } 174 System.out.println("拿走了" + b); 175 } 176 } 177 178 }
反对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,当在一个线程对象上调用stop()方法时,这个线程对象所运行的线程就会立即停止,假如一个线程正在执行:synchronized void { x = 3; y = 4;} 由于方法是同步的,多个线程访问时总能保证x,y被同时赋值,而如果一个线程正在执行到x = 3;时,被调用了 stop()方法,即使在同步块中,它也干脆地stop了,这样就产生了不完整的残废数据。而多线程编程中最最基础的条件要保证数据的完整性,所以请忘记线程的stop方法,以后我们再也不要说“停止线程”了。而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们。结果 很难检查出真正的问题所在。
suspend()方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此 时,其他任何线程都不能访问锁定的资源,除非被"挂起"的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就 会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志,指出线程应该活动还是挂起。若标志指出线程应该挂起,便用 wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。