码迷,mamicode.com
首页 > 编程语言 > 详细

黑马程序员——java多线程基础知识1

时间:2014-05-13 03:24:57      阅读:397      评论:0      收藏:0      [点我收藏+]

标签:java   多线程   thread   虚拟机   基础知识   

多线程

进程是一个正在执行的程序。
cpu在同时执行这些程序,其实是跳跃式的,做快速的切换,时间很短。一个进程可能存在多条路径。迅雷的多路径。每一个进行执行都有一个执行顺序,该顺序是一个执行路径,或这叫一个控制单元。每一个进程至少有一个线程,线程就是进程中的一个独立的控制单元,线程控制进程的执行。jvm启动的时候会有一个进程就叫做java,exe,该进程中至少有一个线程在控制Java程序的执行 ,而且该线程的执行代码在 主函数中。该线程称为主线程。虚拟机至少也有两个线程,一个主线程执行,另一个负责垃圾回收的线程。生活中常见的下载就是多线程的。
存在的意义,能产生同时运行多段代码。

继承thread类
如何自定义去创建线程去执行代码?线程已经被Java封装起来了,会调用windows来创建线程。
thread:允许程序并发地执行多个线程。成为thread的子类,并且重写run(runable对象。)
创建线程的第一种方式:继承thread类
1.建立好一个对象就建立好一个线程
1.定义类执行thread
2.复写run方法。
3.调用线程的start方法,这个方法。 示例中发现:创建并启动一个线程,start。run方法不具备调用线程的能力,是start方法,启动线程,调用run方法。
病毒一直在抢劫cpu资源。cpu切换随机的。内存是瓶颈。
发现运行结果每次都不同,因为每个线程都在获取cpu的执行权,cpu执行到谁,谁就运行。cpu在做着快速的切换已达到看上去是同时运行的结果,这就是多线程的一个特性,随机性谁抢到谁执行,至于执行多长,cpu说了算。
为什么要覆盖run方法。
thread用于描述线程。该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法,run方法用于存储线程运行的代码,主线程放在main里面。你开启线程的意义就是为了执行你指定的代码。复写run方法的目的就让那个自定义的代码存储在run方法中,让进程运行。不能d.run,调用的run方法,主线程执行run,start没有开启线程。start开启线程,执行该线程的run方法,run就是一般调用方法,还是单线程的。


线程的运行状态。                        
创建(调用windows)start开始运行,冻结(睡眠时间)时间结束回到运行,wait()等待。notify唤醒功能。任务管理器的结束进程,才结束。放弃执行资格。消亡:stop和run方法结束。阻塞状态:创建了不一定就马上能执行,要等待cpu来执行,具备运行资格,但没有执行权。冻结状态也是回到阻塞状态。                
获取线程对象以及名称
线程都有自己默认的名称,编号从0开始。(用super改写名称)currentthread()获取当前线程对象
getname()获取线程名称。
局部变量在每一个线程中都有自己独立的空间。

卖票程序
同时出票。
总共只有100张票,你创建了4个,卖了400张。。。用static可以,但是生命周期太长。t1start4次,会出现进程运行。跑圈,前面每跑一圈bang一枪。你已经到了运行状态,再运行没有意义。这也是不ok的,在运行的线程不需要开启。因为没有方法了,因为继承Thread类的run方法存放在类Ticket中
实现runable类。必须实现无参run方法。
实现runnable,实现run
调用:
ticket t=new t不是线程newthread()才是线程

在创建线程对象时就要明确运行那段代码。

package Second;
 class Ticket extends Thread{
int tickets;
public Ticket(int ticket) {
    super();
    this.tickets = ticket;
}
@Override
public void run(){
    while(tickets>0){
        tickets--;
        try {
            Thread.sleep(3);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+">>>"+tickets);
    }
}
}
 public class TicketTest{
     public static void main(String[] args) {
        Ticket ticket=new Ticket(100);
        ticket.start();//由于是继承thread,所以ticket对象本身有start方法
        Thread t1=new Thread(ticket);//这两个是通过创建父类对象调用子类方法的多态现象
        Thread t2=new Thread(ticket);
        t1.start();
        t2.start();
    }
 }//打印结果
/* Thread-0>>>10
Thread-2>>>10
Thread-1>>>8
Thread-0>>>7
Thread-2>>>6
Thread-1>>>5
Thread-2>>>4
Thread-0>>>4
Thread-1>>>2
Thread-0>>>1
Thread-2>>>0
Thread-1>>>0
Thread-0>>>0
*/

创建线程的第二种方式实现thread
thread里可以传ranable的对象,他有这样一个构造函数。
实现runable接口步骤:
1.定义类实现runable接口
2.覆盖runable里run方法
3.通过thread类创建线程对象。
4.ranable接口的子类对象作为实际参数传递给threa类的构造函数
    因为自定义的run方法所属对象是runable接口的子类对象,所以要让线程去执行制定对象的run方法。就必须明确该run方法所属对象。

5.开启start并调用runnable的子类对象run;

class Ticket2 implements Runnable{
int tickets;
public Ticket2(int ticket) {
    super();
    this.tickets = ticket;
}
@Override
public void run(){
    while(tickets>0){
        tickets--;
        try {
            Thread.sleep(3);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+">>>"+tickets);
    }
}
}
public class TicketTest2{
     public static void main(String[] args) {
        Ticket2 ticket=new Ticket2(100);
        //ticket.start();由于是实现Runnable,此时Ticket不在拥有start的方法。
        Thread t1=new Thread(ticket);//这两个是通过创建父类对象调用子类方法的多态现象
        Thread t2=new Thread(ticket);
        Thread t3=new Thread(ticket);
        t1.start();
        t2.start();
        t3.start();
    }
}//打印结果
/*Thread-2>>>9
Thread-1>>>9
Thread-0>>>8
Thread-1>>>6
Thread-0>>>6
Thread-2>>>5
Thread-0>>>3
Thread-2>>>2
Thread-1>>>1
Thread-2>>>0
Thread-1>>>0
Thread-0>>>0*/
实现方式和继承方式的区别:
单继承。方框里的代码需要多线程去执行。学生类继承了person,有了父类,但是你要多线程执行,怎么办。我可以给你提供方法,但是你要符合我的规则。学生是人的一种,学生象runnable
实现方式的好处是避免了但继承的局限性,在定义线程时用实现的方式,而且这方式也可以共享t对象。。。。runnable。
;两种方式最大的不同就是线程代码存放位置的不同,继承存放在thread子类的run方法中,实现时,线程代码存放在接口的子类的run方法中。

安全问题

就是那个判断了,没执行的问题。多语句的时候,同时又操作了共享数据时,在上面的卖票程序中,我们可以看到,结果出现了不该出现的0号票。

写多进程的时候一定要小心安全问题,否则有时测试不出来,但是中病毒了呢,问题的原因在于多条语句在在操作同一个线程的共享数据时,一个线程对多条语句只执行了一部分还没有执行完,另一条线程参与进来执行,导致共享数据的错误。
解决办法

同步代码块
synchronization哪些要同步呢?操作共分享数据的语句。
同步代码块的原理:同步锁。。某段时间类只能由一条线程,直到这段代码执完毕。持有锁的线程可以在同步中执行,没有持有所得线程即使获取cpu的执行权也进不去,因为没有获取锁。火车上的卫生间

同步书写的前提:

1.必须要有两个或者连着以上的线程

2.必须是多个线程 使用同一个锁,才能叫同步。必须保证同一段代码只有一个线程运行。

好处解决了多线的安全问题
弊端:多了一个判断是否上锁,消耗了资源,是在允许消耗的范围内。

同步函数。
1.明确哪些代码是多线程运行代码
2.明确共享数据
3.明确多线程运行代码中那些语句是操作共享数据的。
同步封装代码和函数封装的区别:带有同步性与否。
把synchronized,作为修饰符放在函数上。两种表现形式同步代码块和同步函数。

同步函数的锁是this
怎么只有0线程在执行?因为循环锁住了。别人进不来。。。没搞清楚哪些要同步哪些不用,拿出来,调用show就好了。同步函数用得是哪一个锁呢?函数需要被对象调用。怎么验证这结论:使用两个线程来卖票,一个线程在同步代码块中,一个同步函数,都在执行卖票工作为什么都在run里执行,不执行code?哦,主函数太快了,让主函数睡一会儿。还是出现了错票0 。不安全。两个锁不一样。

静态同步函数的是class对象。静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象,Ticket.class。静态的同步方法使用的锁是所在类的字节码文件对象。类名.class。懒汉式加了锁会比较低效,因为每一个都要判断用双重否定。

懒汉式

死锁:同步中嵌套同步而锁却不同。尽量避免死锁。

黑马程序员——java多线程基础知识1,布布扣,bubuko.com

黑马程序员——java多线程基础知识1

标签:java   多线程   thread   虚拟机   基础知识   

原文地址:http://zhangwei9004.blog.51cto.com/8886503/1409736

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!