黑马程序员--多线程

----------------------- android培训java培训java学习型技术博客、期待与您交流! ----------------------

  线 

       (一)简述多线程:

在单核CPU执行多个线程的情况下,多线程可以运行“同时”运行多部分代码,这样所带来的负面就是运行效率降低,其实,说是同时运行是不严谨的,因为单核CPU无法进行同时运行,所能做的就是CPU做着快速并且是随机的切换动作。

(二)多线程的两种创建形式:一种:继承Thread类,另一种:实现Runnable接口。

1)继承Thread(将类声明为 Thread 的子类,该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例)

开启线程:

线程目的:创建一个线程,去运行指定的代码(执行路径的任务)和其他代码同时运行。

run方法中定义就是线程要运行的任务代码,所以,我们在开启线程时为了运行指定的代码,就只有继承Thread类,并覆写run方法。

但是,需要注意的是:启动线程不能直接使用子类对象调用run方法(这样做就和一般对象调用成员没有什么区别,虽然线程创建了,但是并没有运行。),而是使用子类对象调用线程的start方法,该方法有两个作用,启动线程,调用run方法。直到这个时候线程才开始执行。

ThreadDemo t1=new ThreadDemo();//创建一个线程

              ThreadDemo t2=new ThreadDemo();

              t1.start();//开启一个线程并调用run方法

              t2.start();

获取线程的名称:

java中,线程一创建就带有从0开始的名称:public Thread() { init(null,null, "Thread-" + nextThreadNum(), 0);  },但是,我们想知道当前正在运行线程的名称,那么我们就可以通过Thread.currentThread().getName()方法获取当前线程的名称。

 2)实现Runnable接口

  使用接口Runnable,可以扩展类中的功能,让其中的内容作为线程的任务执行。

Demo d=new Demo();

  Thread t1=newThread(d);//线程对象一创建就得有任务,然后我们在开启线程

Thread t2=new Thread(d);

t1.start();

t2.start();

此时,利用Thread创建好一个线程之后,需要做的就是将Runnable接口的子类作为Thread类的构造函数的参数进行传递(理由:因为线程的任务都封装在Runnable接口的子类对象的run方法中,所以,要在线程对象创建时就必须明确要运行的任务)

总结:

1, 使用Runnable接口,将线程的任务从线程的子类中分离出来,进行了单独的封装。按照面向对象的思想将任务封装成了对象。

2, 避免了java单继承的局限性,可以使用多实现完成。

3, 一般在开发中,常用的是:实现Runnable接口

(三)线程安全隐患

1)产生隐患原因:当一个线程在操作共享数据的多条代码过程中,其他线程参与

运算,就会导致线程安全问题的产生。

2)解决方式Java对于多线程的安全问题提供了专业的解决方式-----同步代码块

格式:

synchronized(对象){

需要被同步的代码

}

案例:卖票程序

class Ticketimplements Runnable{

       private int tick=100;

       Object obj=new Object();

       public void run(){  //覆写了接口中的run方法

              while(true){

                     synchronized(obj){//这儿只要是对象就可以。

                            if(tick>0){

                                   try{Thread.sleep(10);}catch(Exceptione){}

                                   System.out.println(Thread.currentThread().getName()+"--theticket is--"+tick--);

                            }

                     }

              }

       }

}

当某个线程在判断玩tick>0这个条件以后,CPU切换到其他线程,此时,容易产生0号与-1-2号票的问题,这在现实生活中是不允许出现的,此时,我们需要将易产生问题的代码进行同步,让多个线程持有相同的锁,只要某一个线程没有执行完,其它线程就不能执行,这便是同步的好处解决了线程安全隐患问题。

总结:使用同步时,需要注意的地方:

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

2.必须是多个线程使用同一个锁

3.必须保证同步中只能有一个线程在运行。

3)单例模式中的安全问题(懒汉式):

class Single{

       private static Single s=null;

       private Single(){}

       public static Single getInstance(){

              if(s==null){

                     s=new Single();

              }

              return s;

       }

}

此单例设计模式容易产生安全问题,如;当线程—0判断完条件以后,CPU切换到线程—2中,判断为null,则满足条件,此时就产生两个对象,无法报证唯一性。

那么解决方法一:加同步函数public static synchronized Single getInstance(){},这种方法虽然解决了对象唯一性的问题,但是,当对象一进来就需要判断锁,这样程序的效率就大大的降低了。

解决方法二:加同步代码块

class Single{

       private static Single s=null;

       private Single(){}

       public static  Single getInstance(){

              if(s==null){

                     synchronized(Single.class){//注意:这里的锁不能为this,类名.class为通用锁

                            if(s==null){

                                   s=newSingle();

                            }

                 }

              }

              return s;

       }

}

注意锁的使用问题,这里的锁不能是thisgetClass,他们都是非静态的。

使用双重if条件判断语句的原因:当线程—0进来时,使用锁进入第二个if条件判断语句之后,就在那挂着,那么线程—1进来,判断null,判断锁,有线程使用,则进不了,此时,线程—0获取了执行权,返回s,结束线程。线程—1进来拿到锁了,判断第二个if条件不为空,则无法创建对象。此时,再来一个线程—2,判断第一个条件已经不在为空了,此时,直接就进不了,以后的线程都进不来了。使用if判断提高了效率,而加同步代码块,则提高了安全性。

注意:懒汉式,在面试中经常出现,考察点比较多。

 

总结:

1)在同步代码块中,可以使用的锁有:

1,  自己创建一个对象当锁使用。

2,  可以使用this

3,  可以使用类名.class(也可以使类名当作锁:this.getClass())

2)在静态的同步函数中,可以使用的锁是:可以使用类名.class,该函数所属字节码文件对象,因此,我们可以使用getClass方法获取,也就是用当前类名.class表示。

 

 

----------------------- android培训java培训java学习型技术博客、期待与您交流! ----------------------

 

黑马程序员多线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印log之前能够同时开始等待1秒钟。一种解决思路是在线程的run方法中调用parseLog方法,并使用Thread.sleep方法让线程等待1秒钟。另一种解决思路是使用线程池,将线程数量固定为4个,并将每个调用parseLog方法的语句封装为一个Runnable对象,然后提交到线程池中。这样可以实现一秒钟打印4行日志,4秒钟打印16条日志的需求。 第二个问题是如何修改代码,使得几个线程调用TestDo.doSome(key, value)方法时,如果传递进去的key相等(equals比较为true),则这几个线程应互斥排队输出结果。一种解决方法是使用synchronized关键字来实现线程的互斥排队输出。通过给TestDo.doSome方法添加synchronized关键字,可以确保同一时间只有一个线程能够执行该方法,从而实现线程的互斥输出。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [黑马程序员——多线程10:多线程相关练习](https://blog.csdn.net/axr1985lazy/article/details/48186039)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值