解读JAVA多线程
两种不同的实现方式
1、继承Thread类,实现多线程
class hello extends Thread { private String name; public hello() { } public hello(String name) { this.name = name; } public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + "运行 " + i); } } }
public static void main(String[] args) { hello h1=new hello("A"); hello h2=new hello("B"); h1.start(); h2.start(); }
2、实现Runnable接口,实现多线程
class hello implements Runnable { private String name; public hello() { } public hello(String name) { this.name = name; } public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + "运行 " + i); } public static void main(String[] args){ hello h1=new hello("线程A"); Thread demo= new Thread(h1); hello h2=new hello("线程B"); Thread demo1=new Thread(h2); demo.start(); demo1.start(); } }
其实Thread中的run方法调用的是Runnable接口的run方法,Thread和Runnable都实现了run方法,这种操作模式其实就是代理模式。
3、两种实现方式的区别
如果一个类继承Thread,则不适合实现资源共享。但是如果实现Runnable接口的话,则很容易实现资共享。
class hello extends Thread { public void run() { for (int i = 5; i >= 0; i--) { System.out.println("i = " + i); } } public static void main(String[] args) { hello h1 = new hello(); hello h2 = new hello(); h1.start(); h2.start(); } }
运行结果为:
i = 5
i = 4
i = 3
i = 2
i = 1
i = 0
i = 5
i = 4
i = 3
i = 2
i = 1
i = 0
如果使用多线程去实现一个卖票的系统,继承Thread的方法就不行了,要用Runnable的实现方式
class MyThread implements Runnable{ private int ticket = 5; //5张票 public void run() { for (int i=0; i<=20; i++) { if (this.ticket > 0) { System.out.println(Thread.currentThread().getName()+ "正在卖票"+this.ticket--); } } } } public class Test { public static void main(String [] args) { MyThread my = new MyThread(); new Thread(my, "1号窗口").start(); new Thread(my, "2号窗口").start(); } }
运行结果为:
1号窗口正在卖票5
1号窗口正在卖票4
2号窗口正在卖票3
1号窗口正在卖票1
1号窗口正在卖票2
总结
实现Runnable比继承Thread更具有的优势:
1、适合多个相同的程序的线程去处理同一个资源。
2、可避免JAVA单继承限制
3、增加程序的健壮性,代码可被多个线程共享,代码和数据独立
【main方法本身也是一个线程,JAVA的垃圾回收机制也是线程,所以程序运行至少会有两个线程运作】
线程的强制执行
class hello implements Runnable { public void run() { for (int i = 0; i < 3; i++) { System.out.println(Thread.currentThread().getName()); } } public static void main(String[] args) { hello he = new hello(); Thread thread = new Thread(he,"线程"); demo.start(); for(int i=0;i<50;++i){ if(i>10){ try{ thread.join(); //强制执行thread }catch (Exception e) { e.printStackTrace(); } } System.out.println("main 线程执行-->"+i); } } }
线程休眠
class hello implements Runnable { public void run() { for (int i = 0; i < 3; i++) { try { Thread.sleep(2000); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + i); } } public static void main(String[] args) { hello he = new hello(); Thread thread = new Thread(he, "线程"); thread.start(); } }
线程中断
class hello implements Runnable { public void run() { System.out.println("执行run方法"); try { Thread.sleep(10000); System.out.println("线程完成休眠"); } catch (Exception e) { System.out.println("休眠被打断"); return; //返回到程序的调用处 } System.out.println("线程正常终止"); } public static void main(String[] args) { hello he = new hello(); Thread thread = new Thread(he, "线程"); thread.start(); try{ Thread.sleep(2000); }catch (Exception e) { e.printStackTrace(); } thread.interrupt(); //2s后中断线程 } }
线程的优先级
class hello implements Runnable { public void run() { for(int i=0;i<5;++i){ System.out.println(Thread.currentThread().getName()+"运行"+i); } } public static void main(String[] args) { Thread h1=new Thread(new hello(),"A"); Thread h2=new Thread(new hello(),"B"); h1.setPriority(8); h2.setPriority(2); h1.start(); h2.start(); } }
这里注意,并不是优先级越高越先执行,而是看谁先抢到CPU,主线程的优先级为5
线程的礼让
class hello implements Runnable { public void run() { for(int i=0;i<5;++i){ System.out.println(Thread.currentThread().getName()+"运行"+i); if(i==3){ System.out.println("线程的礼让"); Thread.currentThread().yield();//通过yield方法将一个线程的操作暂时交给另一个线程执行 } } } public static void main(String[] args) { Thread h1=new Thread(new hello(),"A"); Thread h2=new Thread(new hello(),"B"); h1.start(); h2.start(); } }
线程的同步和死锁
class hello implements Runnable { public void run() { for(int i=0;i<10;++i){ if(count>0){ try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(count--); } } } public static void main(String[] args) { hello he=new hello(); Thread h1=new Thread(he); Thread h2=new Thread(he); Thread h3=new Thread(he); h1.start(); h2.start(); h3.start(); } private int count=5; }
运行结果为:
5
4
3
2
1
0
-1
这里出现了-1,而代码判断了count>0,出现这样的情况是没有用到线程同步
线程同步就是说在同一个时间段中,只有一个线程能运行,其他线程必须等待着个线程结束后才能被执行
class hello implements Runnable { public void run() { for(int i=0;i<10;++i){ synchronized (this) { if(count>0){ try{ Thread.sleep(1000); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(count--); } } } } public static void main(String[] args) { hello he=new hello(); Thread h1=new Thread(he); Thread h2=new Thread(he); Thread h3=new Thread(he); h1.start(); h2.start(); h3.start(); } private int count=5; }
this 为当前对象,一般吧当前对象作为同步对象
同样也可以采用下面的代码
<div class="line number4 index3 alt1"><code class="java keyword">class</code> <code class="java plain">hello </code><code class="java keyword">implements</code> <code class="java plain">Runnable {</code></div><div class="line number5 index4 alt2"><code class="java spaces"> </code><code class="java keyword">public</code> <code class="java keyword">void</code> <code class="java plain">run() {</code></div><div class="line number6 index5 alt1"><code class="java spaces"> </code><code class="java keyword">for</code> <code class="java plain">(</code><code class="java keyword">int</code> <code class="java plain">i = </code><code class="java value">0</code><code class="java plain">; i < </code><code class="java value">10</code><code class="java plain">; ++i) {</code></div><div class="line number7 index6 alt2"><code class="java spaces"> </code><code class="java plain">sale();</code></div><div class="line number8 index7 alt1"><code class="java spaces"> </code><code class="java plain">}</code></div><div class="line number9 index8 alt2"><code class="java spaces"> </code><code class="java plain">}</code></div><div class="line number11 index10 alt2"><code class="java spaces"> </code><code class="java keyword">public</code> <code class="java keyword">synchronized</code> <code class="java keyword">void</code> <code class="java plain">sale() {</code></div><div class="line number12 index11 alt1"><code class="java spaces"> </code><code class="java keyword">if</code> <code class="java plain">(count > </code><code class="java value">0</code><code class="java plain">) {</code></div><div class="line number13 index12 alt2"><code class="java spaces"> </code><code class="java keyword">try</code> <code class="java plain">{</code></div><div class="line number14 index13 alt1"><code class="java spaces"> </code><code class="java plain">Thread.sleep(</code><code class="java value">1000</code><code class="java plain">);</code></div><div class="line number15 index14 alt2"><code class="java spaces"> </code><code class="java plain">} </code><code class="java keyword">catch</code> <code class="java plain">(InterruptedException e) {</code></div><div class="line number16 index15 alt1"><code class="java spaces"> </code><code class="java plain">e.printStackTrace();</code></div><div class="line number17 index16 alt2"><code class="java spaces"> </code><code class="java plain">}</code></div><div class="line number18 index17 alt1"><code class="java spaces"> </code><code class="java plain">System.out.println(count--);</code></div><div class="line number19 index18 alt2"><code class="java spaces"> </code><code class="java plain">}</code></div><div class="line number20 index19 alt1"><code class="java spaces"> </code><code class="java plain">}</code></div><div class="line number22 index21 alt1"><code class="java spaces"> </code><code class="java keyword">public</code> <code class="java keyword">static</code> <code class="java keyword">void</code> <code class="java plain">main(String[] args) {</code></div><div class="line number23 index22 alt2"><code class="java spaces"> </code><code class="java plain">hello he = </code><code class="java keyword">new</code> <code class="java plain">hello();</code></div><div class="line number24 index23 alt1"><code class="java spaces"> </code><code class="java plain">Thread h1 = </code><code class="java keyword">new</code> <code class="java plain">Thread(he);</code></div><div class="line number25 index24 alt2"><code class="java spaces"> </code><code class="java plain">Thread h2 = </code><code class="java keyword">new</code> <code class="java plain">Thread(he);</code></div><div class="line number26 index25 alt1"><code class="java spaces"> </code><code class="java plain">Thread h3 = </code><code class="java keyword">new</code> <code class="java plain">Thread(he);</code></div><div class="line number27 index26 alt2"><code class="java spaces"> </code><code class="java plain">h1.start();</code></div><div class="line number28 index27 alt1"><code class="java spaces"> </code><code class="java plain">h2.start();</code></div><div class="line number29 index28 alt2"><code class="java spaces"> </code><code class="java plain">h3.start();</code></div><div class="line number30 index29 alt1"><code class="java spaces"> </code><code class="java plain">}</code></div><div class="line number32 index31 alt1"><code class="java spaces"> </code><code class="java keyword">private</code> <code class="java keyword">int</code> <code class="java plain">count = </code><code class="java value">5</code><code class="java plain">;</code></div><div class="line number33 index32 alt2"><code class="java plain">}</code></div>
【当多个线程共享一个资源的时候需要同步,但是过多的同步可能会导致死锁】
关于wait、sleep和notify方法:
1、线程中wait和sleep最大的不同是在等待时,wait会释放锁,而sleep会一直持有锁wait通常被用于线程间的交互,sleep通常用于暂停执行
2、wait方法能使线程阻塞,调用notify方法能唤醒当前备阻塞的线程
3、如果调用某个对象的wait方法,当前线程必须拥有这个对象的monitor(即锁),因此调用wait方法必须在同步块,或者同步方法中进行
4、调用某个对象的wait方法,相当于让当前线程交出此对象的monitor(即锁),然后进入等待状态,等待后继续获得此对象的锁( sleep方法则是使当前线程暂停执行一段时间,从而让其他线程有机会继续执行,但他并不会释放对象锁)
5、notify方法能够唤醒一个正在等待该对象的monitor的线程,当有多个线程都在等待该对象的monitor的话,则只能唤醒其中一个线程,具体唤醒哪个线程则不得而知
6、调用某个对象的notify方法,当前线程也必须拥有这个对象的monitor,因此调用notify()方法必须在同步块或者同步方法中进行
7、notify和notifyAll方法只是唤醒等待该对象的monitor的线程,并不决定哪个线程能够获取到monitor