黑马程序员----java基础:多线程

王朝学院·作者佚名  2016-05-28
窄屏简体版  字體: 小  |  中  |  大  |  超大  

黑马程序员----java基础:多线程------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

如果一次只完成一个事情,还是比较容易实现的,但事实上很多事情都是同时执行的,java为了模拟这种状态,引入了线程机制。

当程序同时完成多个事情时,就是所谓的多线程程序。

在一个时刻,单核的cpu只能运行一个程序。而我们看到的同时运行效果,只是cpu在多个进程间做着快速的随机切换动作。

所以说多线程解决了多部分同时运行的问题,但是线程太多的话肯定会影响效率。

首先老规矩一张图来展现我们本次要介绍的内容:

一、实现方式实现线程的方式一共有两种---继承Thread类和实现Runnable接口。

1、继承Thread类。

a、定义类继承Thread。

b、复写Thread中的run方法。

c、创建定义类的实例对象。

d、调用start方法启动线程。

class TestThread extends Thread // a、定义类继承Thread。{ public void run() //b、复写Thread中的run方法。 { for (int x = 0; x < 50 ;x++ ) { System.out.PRintln(Thread.currentThread().getName()+"......"+x); } }}class Demo{ public static void main(String[] args) { TestThread t1= new TestThread();//c、创建定义类的实例对象。 TestThread t2= new TestThread(); t1.start(); //d、调用start方法启动线程。 t2.start(); }}

2、实现runnable接口

a、定义类实现Runnable的接口。

b、覆盖Runnable接口中的run方法。

c、通过Thread类创建线程对象。

d、调用start方法启动线程。

class TestThread implements Runnable//a、定义类实现Runnable的接口。{public void run()// b、覆盖Runnable接口中的run方法。{for (int x = 0; x < 50 ;x++ ){System.out.println(Thread.currentThread()+"++++++"+x);}}}class Demo{public static void main(String[] args) {TestThread d = new TestThread();Thread t1 = new Thread(d);Thread t2 = new Thread(d);//c、通过Thread类创建线程对象。t1.start(); //d、调用start方法启动线程。t2.start();}}

3、实现Runnable接口的优势

实际开发中,我们经常使用第二种方式做多线程,它的优势在于

a、避免了按照面向对象的思想将任务封装成对象。

b、避免了java单继承的局限性。

二、线程的生命周期线程具有生命周期,其各个生命周期的关系如下图。

三、线程安全实际开发中,使用多线程的情况有很多,比如火车站售票系统,当有多个线程做取票动作时,假设此时只有一张票,一线程将票售出,此时二线程完成了判断是否有票动作,并得出票数大于0结论。此时执行售票就会产生负数。

1、安全问题产生的原因

a、多个线程在操纵共享数据

b、操纵共享数据的代码有多条。

2、解决办法--同步

将多条操作共享数据的线程代码封装起来,当有线程执行这些代码时候,其他线程不可参与。

a、同步代码块

synchronized(obj){//需要同步的代码}

b、同步函数

public synchronized void show() { //需要同步的代码}

3、同步函数和同步代码块的区别

同步函数的锁是this

同步代码块的锁是任意的(也可以是this)

实际开发中建议用同步代码块。

4、同步的利弊

好处:解决了多线程的安全问题。

弊端:多个线程需要判断锁,较为消耗资源。

5、静态函数代码块

如果同步函数被静态修饰后,使用的锁是什么呢?设计模式中的单例模式给大家展示。

//懒汉式class Single{ private static Single s = null; private Single(){} public static Single getInstance() { if(s == null) { synchronized(Single.class) //静态方法写---类名.class { if(s==null) s = new Single(); } } return s; }}

四、线程间通信线程间的通信其实就是多个线程共享同一个资源。

class ResorceDemo{ public static void main(String[] args) { Resorce r = new Resorce(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); }}class Resorce //定义一个资源{ String name; String sex; boolean flag = false;}class Input implements Runnable//写入资源{ Resorce r; Input(Resorce r) { this.r = r; } public void run()//复写run方法 { int x = 0;//x相当于一个标志. while (true) { synchronized(r) { if (r.flag == true) { try { r.wait(); } catch (InterruptedException e) { } } else { if (x==0) { r.name = "mike"; r.sex = "nan"; } else { r.name = "傻妞"; r.sex = "妞妞妞妞i牛i牛ii牛"; } r.flag = true; r.notify();//唤醒 } x = (x+1)%2;//x在0和1之间相互交替. } } }}class Output implements Runnable//读取资源{ Resorce r; Output(Resorce r) { this.r = r; } public void run() { while (true)//无限循环 { synchronized(r) { if (r.flag == false) { try { r.wait(); } catch (InterruptedException e) { } } else { System.out.println(r.name + "..."+r.sex); r.flag = false; r.notify(); } } } }}

五、常见操作方法1,wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。2,notify():唤醒线程池中一个线程(任意).3,notifyAll():唤醒线程池中的所有线程。4,setPriority():设置优先级5,yield():暂停当前线程,让其他线程执行。

当然,这些常见的操作方法在API中都可以查到,这不是我要说的重点,下面来对这些方法做一下比较。

(1)wait 和 sleep 区别?

1,wait可以指定时间也可以不指定。 sleep必须指定时间。

2,在同步中时,对cpu的执行权和锁的处理不同。 wait:释放执行权,释放锁。 sleep:释放执行权,不释放锁。

(2)wait(),notify(),notifyAll(),用来操作线程为什么定义在了Object类中?

a,这些方法存在与同步中。

b,使用这些方法时必须要标识所属的同步的锁。同一个锁上wait的线程,只可以被同一个锁上的notify唤醒。

c,锁可以是任意对象,所以任意对象调用的方法一定定义Object类中。

六、总结多线程本身也是比较复杂的问题,要完全理解它还需要时间,所谓孰能生巧,这些知识还是要多看多练多去实践才能真正掌握。

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航