黑马程序员技术交流社区

标题: 写了多线程的总结大家给点意见 [打印本页]

作者: java木    时间: 2014-5-30 01:39
标题: 写了多线程的总结大家给点意见
            ---------------------- <a target="blank">ASP.Net+Unity开发</a>、<a target="blank">.Net培训</a>、期待与您交流! ----------------------
      
   java 多线程学习总结
多线程技术大大提高了软件程序的效率,尤其是当程序需要与硬件交互时。现在的软件产品越来越重视用户体验,而软件产品的执行效率直接决定了用户体验的好坏。
对多线程的学习需要了解以下几个概念。
进程:
   是一个正在执行的程序,每个进程都有执行顺序。该顺序是一个执行路径或一个控制单元。
线程:就是进程中的控制单元,线程控制着进程的执行。一个进程至少包含一个线程。
java开启线程的方式有两种。(准确的说java创建线程的的方式只有一种,就是创建 Thread类或其子类的对象。)
方式一:1
1.继承Thread类,复写其run()方法。将要开启线程执行的代码写入run()方法中。
2.调用start()方法开启线程。
具体代码如下:
//创建类,覆盖run方法
class MyThread extends Thread{
run(){
while(true){
  System.out.println("Hello Thread");
}
}
}
//启动线程
public static void main(String[]args){
MyThread my=new MyThread();
my.start();
}
第一种开启线程的思想是:根据java的面向对象思想。如果希望自己的类能成为一个线程并被JVM作为一个单独的线程独立执行的话,就应该加入该体系中,所以要继承Thread类。覆盖run方法是因为,run方法是用来存放线程要执行的代码,重写run方法就可以让我们创建的线程按我们要求的方式执行。
第二种方式:
1.定义类实现Runnable 接口。
2.覆盖run方法将需要运行的代码存放进去。
3.通过Thread类创建线程对象。
4.将实现Runnable接口的对象作为实际参数传入Thread的构造函数中。
5.调用Thread对象的start方法开启线程。
具体代码如下
//定义类实现Runnable接口,并复写run方法。
public class MyThread implements Runnable{
public void run(){
  while true(){
   System.out.println("Hello Thread")
  }
}
}
//开启线程
public static void main(String[]args){
      MyThread myt=new MyThread();
  Thread t=new Thread (myt);
  t.start();
}
第二种方式并不像第一种,我们要继承Thread类,创建一个线程。我们用第二中方式开启一个线程,只需要定义一个类实现Runnable 接口。让该类具备可以被作为一个独立的执行顺序,被线程运行的功能。把他的对象传入Thread的构造函数中。调用Thread对象的start()就可开启线程。
java 为什么要如此设计多线程的两种开启方式呢?
弄清这个问题,我们可以从这两种开启多线程方式的区别入手。
java两种多线程开启方式的比较:
1.如果一个类通过继承Thread类来开启线程,它就不能有别的父类。这就受到了java单继承的限制。而第二种方式,只需实现Runnable接口,仍然可以继承别的类,这可要灵活多了。
2.线程执行的代码不同,第一种方式代码是存在 Thread 类的run方法中。而第二种方法代码是存在实现Runnable接口类的run方法中。
3.从程序设计角度来说。如果我们的需求是创建一个多线程,并需要修改Thread类的一些基本方法时,就需要用第一种方式。而我们只是需要开启多线程时,只需要使用第二中即可。
所以,以后选择这两种方式,只需根据需求而定。不过大多时候我们的需求都只是需要开启线程。那么第二种开启线程方式是最常用的的。java也同样建议我们用第二种方式。
避免了单继承的局限性,可以使线程共享资源,在一定程度上可以说节省了内存。
线程的运行状态(生命周期)
                   wait()或
       start()            sleep(time)|
被创建状态----->运行状态----->冻结状态
            stop( ) |    <----
      或run()中的代码执行完毕 |     sleep时间到或
       |   notify()
            消亡状态
           
上图还省略了每个线程都会处于的一种状态,临时状态。
临时状态是指每个线程在处于运行状态时,具有了执行权,但没有被CPU执行,既没有运行权,我们亦可以将其称为阻塞状态。(多线程同时运行的原理是CPU瞬时间在各个线程间来回切换运行,所以我们感觉上是各个线程同时运行。qq和酷狗音乐同时玩着。)

线程安全问题:
当多线程操作共享数据时,就会出现多线程安全问题。请看以下示例代码:
package com.heima.duoxiancheng;
/*
* 本文件将用代码方式模仿现实中车站多窗口卖票情景
* 并描述多线程安全问题产生原因,和解决方法。
*/
public class DuoXianChengAnQuan {
public static void main(String[] args) {
  // TODO Auto-generated method stub
  TicketThread th=new TicketThread();
  Thread t1=new Thread(th);
  Thread t2=new Thread(th);
  Thread t3=new Thread(th);
  Thread t4=new Thread(th);
  t1.start();
  t2.start();
  t3.start();
  t4.start();
}
}
class TicketThread implements Runnable {
int ticket = 1000;
Object obj=new Object();
public void run() {
  while (true) {
    synchronized (obj) {
     /*synchronized同步语句块中是多条句
       操作线程共享数据。会有发生多线程安全问题的可能。假设在ticket=1时,线程一经过if语句进入这里,由于cpu在切换到别的线程,它进入阻塞状态停在这里,现程二又进入了,然后线程一又被cpu执行,将ticket变为0,线程二执行,注意这时它就会将ticket变为-1.这就是对ticket的错误操作(ticket是大于0的)。这时synchronized语句块的作用就体现出来了。它将会将这些语句锁起来,在已有一个线程进来时,直到该线程执行完所有语句,把锁打开时,synchronized语句块才允许另一个线程进来。这就从而解决了多线程安全问题。
      */
     if (ticket > 0) {
     try {
      Thread.sleep(10);//该方法是       为了让多线程安全问题更容易产生。
     } catch (InterruptedException e) {
      e.printStackTrace();
     }
     ticket--;
     System.out.println("窗口" + Thread.currentThread().getName()
       + "卖出第" + ticket + "张火车票");
    }
   
   }
  }
}
}
从以上代码中可以看出,多线程安全问题的原因是,有多条语句操作多线程共享数据,由于多线程在运行时CPU的随机切换线程执行,会导致一个线程没有执行完那些语句,另外的线程就又参与进来执行,导致数据处理的错误,引发了多线程安全问题。
多线程安全问题的的解决:
在知道多线程安全问题引发的原因,那解决他的原理也就一目了然了。
对多条线程共享数据的操作语句,要保证只能让一个线程执行完,再让另一个线程执行。在执行过程中不能让让别的线程参合进来。java中提供了专业的解决办法synchoized的语句块和synchoized函数。
格式如下
synchoized(对象名){
操作共享数据的代码
}
synchoized void play(){
操作共享数据的代码
}



作者: Blüe-wǒlf    时间: 2014-6-1 20:52
貌似你的进度和我差不多呢,兄弟
作者: 张辉玉    时间: 2014-6-2 15:55
进来学习了。
作者: 淡淡柠檬茶    时间: 2014-6-2 15:59
我也进来复习了哥们 不过我认为你应该在加上

同步的前提:
1、必须要有两个或者两个以上的线程。
2、必须是多个线程使用同一个锁。

同步函数的锁是this
静态同步函数的锁是Class对象

单例设计模式之懒汉式:
class Single
        {
                private Single(){}
                private static Single single = null;
                public  staticSingle getInstance()
                        {
                                if(single==null)
                                        {//避免每次都判断锁,只有当对象为null的情况下才判断
                                                synchronized(Single.class)
                                                {
                                                        if(single==null)/*如果一个线程跑到第一个if后死了,另一个线程进来创建了对象释放了锁,然后那个线程醒了,进来后还要判断*/
                                                        single =new Single();
                                                }
                                        }
                                return single;
                        }
        }

wait() notify() notifyAll()都是用在同步中,因为要对持有监视器(锁)的线程操作,所以使用在同步中,因只有同步中有锁。
为什么这些操作线程的方法要定义在object类中呢?
答:因为这些方法在操作同步中的线程时,都必须要标示他们所操作线程只有的锁。
只有同一个锁上的被等待线程可以被同一个锁上的线程被notify唤醒。同时不可以对不同所中的线程进行唤醒。
也就是说等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法定义在object中。

Notify():往往唤醒线程池中的第一个,所以可能唤醒本方导致数据错乱全部等待。可以用notifyall全部唤醒。
当出现多个生产者消费者同时要做这件事情的时候要用循环while和notifyall,(通用1.while判断标记,2.把对方唤醒)当只有一个生产者和消费者时可以用if

停止线程:Stop方法已过时,如果停止线程呢:只有一种,run()方法结束
原理:开启多线程运行,运行代码通常是循环。只要控制循环,皆可以让run方法结束即线程结束。

守护线程:线程对象.setDaemon(true);将该线程标记为守护线程或用户线程。
当正在运行的线程都是守护线程时,Java虚拟机退出,程序结束。

多线程(Join方法)
特点:当A线程执行到了B线程的.join()方法时,那么A线程就会等待B线程都执行完A才会执行。它可以用于临时加入线程执行



作者: 唤月    时间: 2014-6-2 22:09
我今天刚看完多线程 ....复习下
作者: java木    时间: 2014-6-3 01:45
谢谢了。。。。。。
作者: Blackay    时间: 2014-6-3 08:28
这是你自己写的?还是copy的
作者: java木    时间: 2014-6-4 22:37
自己写的这只是一部分
作者: IStudying    时间: 2014-6-22 23:54
学习学习了
作者: 王飞163    时间: 2014-6-22 23:58
赞一个,进来学习下
作者: 张益达    时间: 2014-6-23 08:40
日 这都给技术分   这根本就跟无异于水贴啊
作者: 钟翠翠    时间: 2014-6-23 09:02
哇 楼主好有心 借用了
作者: caohaikuan    时间: 2014-6-23 09:17
1、必须要有两个或者两个以上的线程。
2、必须是多个线程使用同一个锁。
作者: crazystraw    时间: 2014-6-23 09:38
复习一遍
作者: 花花拉拉    时间: 2014-6-23 09:41
学习学习
作者: 王振2014    时间: 2014-6-23 09:52
咱们是不是应该抛弃Synchronized,使用ReentrantLock啊,不得跟着软件更新走啊
作者: 王振2014    时间: 2014-6-23 09:53
我练习的时候都是用的同步锁,没用synchronized,感觉搞懂他的原理就可以了
作者: Rodgers    时间: 2014-6-23 15:14
支持一下楼主啊!!
作者: wojiaojay    时间: 2014-6-23 17:44
兄弟,在黑马论坛不用加    ---------------------- <a target="blank">ASP.Net+Unity开发</a>、<a target="blank">.Net培训</a>、期待与您交流! ----------------------  这个是在博客中需要加的




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2