黑马程序员_多线程

来源:互联网 发布:统计软件spss 编辑:程序博客网 时间:2024/05/10 01:51
android培训、java培训、期待与您交流!

进程正在进行中的程序(直译).                 

线程:就是进程中一个负责程序执行的控制单元(执行路径)

一个进程中可以多执行路径,称之为多线程。

一个进程中至少要有一个线程。

开启多个线程是为了同时运行多部分代码。

多线程好处解决了多部分同时运行的问题还可以提高效率,非主应用(下载)。

多线程的弊端:线程太多回收效率的降低。

其实应用程序的执行都是cpu在做着快速的切换完成的。但是这个切换是随机的。

Cpu执行到谁,谁就运行。调用线程的start方法:该方法有两个作用--启动线程--调用run方法。


Thread类用于描述线程,线程是需要任务的。所以Thread类也对任务的描述。

         这个任务就通过Thread类中的run方法来体现。也就是说,run方法就是封装自定义线程运行任          务的函数。

         run方法中定义就是线程要运行的任务代码

         开启线程是为了运行指定代码,所以只有继承Thread类,并复写run方法。

         将运行的代码定义在run方法中即可。Start方法是父类的,然后调用的时候就会调用子类复写的run方法。


创建线程的两种方法:

第一种方式:

1.继承Thread类

2.覆写Thread中的run方法

3.创建Thread的子类对象创建线程

4 调用start()开启线程。

可以通过Thread的getName方法获取线程的名称  Thread-编号(从0开始).


/*需求:储户,两个,每个都到银行存钱每次存100,,共存三次。*/class Bank{         privateint sum;         publicsynchronized void add(int num)//同步函数{                           sum= sum + num;                           try{Thread.sleep(10);}catch(InterruptedExceptione){}                           System.out.println("sum="+sum);         }}class Cus implements Runnable{         privateBank b = new Bank();         publicvoid run(){                  for(int x=0; x<3; x++)                  {                           b.add(100);                  }}}class BankDemo {         publicstatic void main(String[] args) {                  Cus c = new Cus();                  Thread t1 = new Thread(c);                  Thread t2 = new Thread(c);                  t1.start();                  t2.start();         }}


------------------------------------------------------------------------------------------------------------------------------------------

 

创建线程的第二种方式:实现Runnable接口。

1,定义类实现Runnable接口。

2,覆盖接口中的run方法,将线程的任务代码封装到run方法中。

将线程要运行的代码存放在该run方法中。

3,通过Thread类创建线程对象,

4,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。

                  为什么要将Runnable接口的子类对象传递给Thread的构造方法,因为自定义的run方法所属 的对象是Runnable接口的子类对象。所以要让线程去执行指定对象的run方法。就必须要明确 run方法所属对象。       

5,调用线程对象的start方法开启线程。

//调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。线程的任务都封装   Runnable接口子类对象的run方法中。所以要在线程对象创建时就必须明确要运行的任务。

-----------------------------------------------------------------------------------------------------------------------------------------

class Demo implements Runnable//extends Fu {//准备扩展Demo类的功能,让其中的内容可以作为线程的任务执行。通过接口的形式完成。         publicvoid run(){                  show();         }publicvoid show(){                  for(int x=0; x<20; x++){                           System.out.println(Thread.currentThread().getName()+"....."+x);                  }}}class ThreadDemo{         publicstatic void main(String[] args) {                     Demo d = new Demo();                  Thread t1 = new Thread(d);                  Thread t2 = new Thread(d);                  t1.start();                  t2.start();         }}


-------------------------------------------------------------------------------------------------------------------

 

实现Runnable接口的好处:

1,将线程的任务从线程的子类中分离出来,进行了单独的封装。

                  按照面向对象的思想将任务的封装成对象。

|--继承Thread:线程代码存放在Thread子类run方法中。

|--实现Runnable,线程代码存放在接口的字累的run方法中。

2,避免了java单继承的局限性。所以,创建线程的第二种方式较为常用


多线程下的单例

//饿汉式

class Single{         privatestatic final Single s = new Single();         privateSingle(){}         publicstatic Single getInstance(){                  return s;         }}


//懒汉式

加入同步为了解决多线程安全问题。


<p><span style="color:gray;">class Single{</span></p><p><span style="color:gray;">         privatestatic Single s = null;</span></p><p><span style="color:gray;">         privateSingle(){}</span></p><p><span style="color:gray;">         publicstatic Single getInstance(){</span></p><p><span style="color:gray;">                  </span><strong><span style="color:green;">if(s==null){</span></strong></p><p><strong><span style="color:green;">                           synchronized(Single.class)           {</span></strong></p><p><strong><span style="color:green;">                                    if(s==null)</span></strong></p><p><span style="color:gray;">                                             s= new Single();</span></p><p><span style="color:gray;">                           }</span></p><p><span style="color:gray;">                  }return s;</span></p><p><span style="color:gray;">         }}</span></p><p><span style="color:gray;">class SingleDemo{</span></p><p><span style="color:gray;">         publicstatic void main(String[] args) {</span></p><p><span style="color:gray;">                  System.out.println("HelloWorld!");</span></p><p><span style="color:gray;">         }}</span></p>

线程运行的状态:

创建==Thread声明一个对象或者Thread子类声明一个对象,

运行,对象调用start()方法,

中断(冻结,放弃执行资格)

有三种情况:    wait()等待、、须唤醒调用:notify()

sleep(时间,毫秒值),等待固定值。

③阻塞,就是有执行权利但是没有cpu,常规等待、、

cpu切换

消亡,run方法结束,或者是强制结束stop()方法。

 

线程名称:两个方法:getName,setName

由     Thread-1

Thread-0、、、线程默认名称。

线程构造方法:

Thread()
分配新的 Thread 对象。

Thread(Runnable target)
分配新的 Thread 对象。

Thread(Runnable target, String name)
分配新的 Thread 对象。

Thread(String name)
分配新的 Thread 对象。

Thread(ThreadGroup group, Runnable target)
分配新的 Thread 对象。

Thread(ThreadGroup group, Runnable target,String name)
分配新的 Thread 对象,以便将 target 作为其运行对象,将指定的 name 作为其名称,并作为 group 所引用的线程组的一员。

Thread(ThreadGroup group, Runnable target,String name, long stackSize)
分配新的 Thread 对象,以便将 target 作为其运行对象,将指定的 name 作为其名称,作为 group 所引用的线程组的一员,并具有指定的堆栈大小

Thread(ThreadGroup group, String name)
分配新的 Thread 对象。

 

其中比较重要的一些方法:

void run()

               如果该线程是使用独立的 Runnable 运行对象构造的,则调用该Runnable 对象的 run 方                     法;否则,该方法不执行任何操作并返回。

void setName(String name)

                  改变线程名称,使之与参数 name 相同。
         static void sleep(long millis)

              在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度                 程序精度和准确性的影响。

static void sleep(long millis, int nanos)

             在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系                   统计时器和调度程序精度和准确性的影响。

void start()

             使该线程开始执行;Java虚拟机调用该线程的 run 方法。
         String toString()

          返回该线程的字符串表示形式,包括线程名称、优先级和线程组。

static void yield()

          暂停当前正在执行的线程对象,并执行其他线程。

static Thread currentThread()

          返回对当前正在执行的线程对象的引用。

唤醒机制

------>wait();

notify();

notifyAll();

都使用在同步中,因为要对持有监视器(锁)的线程操作。

所以要使用在同步中,因为只有同步才具有锁。

为什么这些操作线程的方法要定义Object类中呢?唯一这些方法在操作同步中的线程时,都必须要标 识它们所操作线程只有的锁,只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。

不可以对不同锁中的线程进行唤醒。

也就是说,等待和唤醒必须是同一个锁。

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

class Resource{

         privateString name;

         privateString sex;

         privateboolean flag = false;

         public synchronized voidset(String name,String sex){

                  if(flag)

                           try{this.wait();}catch(InterruptedExceptione){}

                  this.name = name;

                  this.sex = sex;

                  flag = true;

                  this.notify();

         }publicsynchronized void out(){

                  if(!flag)

                           try{this.wait();}catch(InterruptedExceptione){}

                  System.out.println(name+"...+...."+sex);

                  flag = false;

                  notify();

【原有且优化后期】

         }}

//输入

class Input implements Runnable{

         Resourcer ;

//       Objectobj = new Object();

         Input(Resource r){

                  this.r = r;

         }publicvoid run(){

                  int x = 0;

                  while(true){

                           if(x==0){

                                    r.set("mike","nan");

                           }else{

                                    r.set("丽丽","女女女女女女");

                           }x= (x+1)%2;

                  }}

------->优化(run方法):

if(x==0)

r.set("mike","nan");

else

         r.set("丽丽","女女女女女女");

x = (x+1)%2;

 

}

//输出

class Output implements Runnable{

         Resourcer;

//       Objectobj = new Object();

         Output(Resourcer){

                  this.r = r;

         }public void run(){

                  while(true){

                           r.out();

                  }}

------->优化(run方法):

while(true)

         r.out();

}class ResourceDemo3{

         publicstatic void main(String[] args) {

                  //创建资源。

                  Resource r = new Resource();

                  //创建任务。

                  Input in = new Input(r);

                  Output out = new Output(r);

                  //创建线程,执行路径。

                  Thread t1 = new Thread(in);

                  Thread t2 = new Thread(out);

                  //开启线程

                  t1.start();

                  t2.start();

------->优化(六句变两句)

new Thread(newInput(r)).start();

new Thread(newOutput(r)).start();

         }}

升级JDK1.5中提供了多线程升级解决方案。

将同步synchronized 替换成了显示的Lock操作。

将Object中的wait()//notify()//notifyAll(),替换了Condition对象。

该对象可以Lock锁 进行获取。

///实现了本方只唤醒对方的操作。-->一个锁可以对应多个Condition,,,就可以制定唤醒了。

Finally--->一定要执行。用于释放lock锁。

class Test implements Runnable{         privateboolean flag;         Test(booleanflag){       this.flag = flag;}         publicvoid run(){                  if(flag){                           while(true)                                    synchronized(MyLock.locka){                                             System.out.println(Thread.currentThread().getName()+"..if   locka....");                                             synchronized(MyLock.lockb) {                                                      System.out.println(Thread.currentThread().getName()+"..if                                                                                                                 lockb....");                                             }}}                  else{                           while(true)                                                      synchronized(MyLock.lockb){                                             System.out.println(Thread.currentThread().getName()+"..else           lockb....");                                             synchronized(MyLock.locka){                                                      System.out.println(Thread.currentThread().getName()+"..else          locka....");                                             }}}}}class MyLock{         publicstatic final Object locka = new Object();         publicstatic final Object lockb = new Object();}class DeadLockTest {         publicstatic void main(String[] args) {                  Test a = new Test(true);                  Test b = new Test(false);                  Thread t1 = new Thread(a);                  Thread t2 = new Thread(b);                  t1.start();                  t2.start();         }}


停止线程:

Stop()过时了。

只有一种方法:run()方法结束。

①     开始多线程运行,运行代码通常都是循环结构。

只要控制住循环,就可以让run方法结束,也就是线程结束。

②特殊情况:

当线程处于了冻结状态。

就不会读取到标记,那么线程就不会结束。

当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行处理。强制让线程恢复到运 行状态中来。这样就可以操作标记让线程结束。

Join:

当A线程执行到了B线程的。Jion()方法,A就会等待。等B线程都执行完,A才会执行。

Join可以用来临时加入线程执行。(比较少使用。Join跑出了异常,需要注意。)

守护线程:毕老师使用的是圣斗士和雅典娜,中国来讲就是西游记。

优先级和yield

优先级表示的是,运行频率。常用:1,5,10.对应的是:MAX_PRIORITY;MIN;NORM

Yield:表示的是暂停当前正在执行的线程对象,并执行其他线程。

public static void yield()

独立运算,相互之间不相干的时候单独封装下即可。

多线程总结:

1,进程和线程的概念。

         |--进程:

         |--线程:

 

2jvm中的多线程体现。

         |--主线程,垃圾回收线程,自定义线程。以及他们运行的代码的位置。

 

3,什么时候使用多线程,多线程的好处是什么?创建线程的目的?

         |--当需要多部分代码同时执行的时候,可以使用。

 

4,创建线程的两种方式。★★★★★

         |--继承Thread

                  |--步骤

         |--实现Runnable

                  |--步骤

         |--两种方式的区别?

5,线程的5种状态。

         对于执行资格和执行权在状态中的具体特点。

         |--被创建:

         |--运行:

         |--冻结:

         |--临时阻塞:

         |--消亡:

6,线程的安全问题。★★★★★

         |--安全问题的原因:

         |--解决的思想:

         |--解决的体现:synchronized

         |--同步的前提:但是加上同步还出现安全问题,就需要用前提来思考。

         |--同步的两种表现方法和区别:

         |--同步的好处和弊端:

         |--单例的懒汉式。

         |--死锁。

7,线程间的通信。等待/唤醒机制。

         |--概念:多个线程,不同任务,处理同一资源。

         |--等待唤醒机制。使用了锁上的 wait notify notifyAll. ★★★★★

         |--生产者/消费者的问题。并多生产和多消费的问题。 while判断标记。用notifyAll唤醒对方。★★★★★

         |--JDK1.5以后出现了更好的方案,★★★

                  Lock接口替代了synchronized 

                  Condition接口替代了Object中的监视方法,并将监视器方法封装成了Condition

                  和以前不同的是,以前一个锁上只能有一组监视器方法。现在,一个Lock锁上可以多组监视器方法对象。

                  可以实现一组负责生产者,一组负责消费者。

         |--waitsleep的区别。★★★★★

8,停止线程的方式。

         |--原理:

         |--表现:--中断。

9,线程常见的一些方法。

         |--setDaemon()

         |--join();

         |--优先级

         |--yield();

         |--在开发时,可以使用匿名内部类来完成局部的路径开辟。




0 0
原创粉丝点击