黑马程序员——线程实现问题

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

一、多线程

1.创建线程:

创建线程方式第一种:继承Thread类。

步骤:

(1)定义一个类继承Thread类。

(2)覆盖Thread类中的run方法。

(3)直接创建Thread的子类对象创建线程。

(4)调用start方法开启线程并调用线程的任务run方法执行

<span style="font-size:18px;">public class Thread1 extends Thread{
	public static void main(String[] args) {
		Thread thread1= new Thread1();
		Thread thread2= new Thread1();
		thread1.start();
		thread2.start();
	}
	public void run() {	
	}
}</span>

可以通过ThreadgetName获取线程的名称 Thread-编号(0开始)

主线程的名字就是main

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

将运行的码定义在run方法中即可。

run方法就是封装自定义线程运行任务的函数。run方法中定义就是线程要运行的任务代码。

当前运行线程名称Thread.currentThread().getName()

Stop()            线程任务的结束

Sleep(time)    线程冻结,时间到了自动运行

wait()  notify()唤醒


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

1,定义类实现Runnable接口。

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

3,通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。为什么?因为线程的任务都封装在Runnable接口子类对象的run方法中。所以要在线程对象创建时就必须明确要运行的任务。

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

<span style="font-size:18px;">Class Demo implements Runnable {
Public void run( ){…};
public static void main(String[] args) {
Demo d = new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
t1.start();
t2.start();
}<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span></span>

实现Runnable接口的好处:

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

2,避免了java单继承的局限性。

 

线程安全问题产生的原因:

1,多个线程在操作共享的数据。

2,操作共享数据的线程代码有多条。

当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算。

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

解决思路:

就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,

其他线程时不可以参与运算的。

必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。 

同步代码块的格式:

synchronized(对象)

{

需要被同步的代码 ;

}

同步的好处是解决了线程的安全问题,相对降低了效率,因为同步外的线程都会判断同步锁

同步的前提:同步中必须有多个线程并使用同一个锁。

同步函数的使用的锁是this

同步函数和同步代码块的区别:

(1)同步函数的锁是固定的this

(2)同步代码块的锁是任意的对象。

(3)建议使用同步代码块。

静态的同步函数使用的锁是  该函数所属字节码文件对象 

可以用 getClass方法获取,也可以用当前  类名.class 表示。

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

加入双重判断是为了解决效率问题。

<span style="font-size:18px;">Class Single{
private static Single s =null;
private single(){ }
public static Single getInstance(){
   If(s==null){
      synchronized(Single.class){
         if(s==null)
         s= new Single();
}	
}
return s;
}
}
死锁:常见情景之一:同步的嵌套。
Class Test implements Runnable{
Private int num =100;
Object obj = new Object();
Private boolean flag =true;
Public void run(){
  if(flag){
while(true){
   synchronized(obj){
       show();
       }
   }
}
else 
while(true)
  this.show();
}
Public synchronized void show(){
   Synchronized(obj){
      If(num>0){
        Try{Thread.sleep(10);}catch(InterruptedException e){}
       }
   }
}
public static void main(String[] args) {
Test t = new Test();
Thread t1= new Thread(t);
Thread t2 = new Thread(t);

t1.start();
try{Thread.sleep(10);}catch(InterruptedException e){}
 t.flag = false;	
t2.start();
}
}</span>

1wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。

2notify():唤醒线程池中一个线程(任意).

3notifyAll():唤醒线程池中的所有线程。

 注意“:

(1)这些方法都必须定义在同步中。因为这些方法是用于操作线程状态的方法。

必须要明确到底操作的是哪个锁上的线程。

 (2)if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。

while判断标记,解决了线程获取执行权后,是否要运行!

 (3)notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。

notifyAll解决了本方线程一定会唤醒对方线程的问题。

 

Lock接口: 出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作。同时更为灵活。可以一个锁上加上多组监视器。

lock():获取锁。

unlock():释放锁,通常需要定义finally代码块中。

wait 和 sleep 区别?

(1)wait可以指定时间也可以不指定。

   sleep必须指定时间。

(2)在同步中时,对cpu的执行权和锁的处理不同。

wait:释放执行权,释放锁。

sleep:释放执行权,不释放锁。

停止线程:

1stop方法。2run方法结束。

怎么控制线程的任务结束呢?

       任务中都会有循环结构,只要控制住循环就可以结束任务。控制循环通常就用定义标记来完成。

但是如果线程处于了冻结状态,无法读取标记。

如何结束呢?

         可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu的执行资格。 当时强制动作会发生了InterruptedException,记得要处理

t1.join();//t1线程要申请加入进来,运行。临时加入一个线程运算时可以使用join方法。

Yield() 暂停当前线程,执行其他线程



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
黑马程序员线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印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、付费专栏及课程。

余额充值