黑马程序员_多线程

进程与线程:进程是正在执行的程序,而线程是进程中用于控制程序执行的控制单元,其通过调用父进程中的资源执行任务。
进程可以有多个线程且其至少有一个线程。线程必须有且只有一个父进程。

当JVM启动时,就有两个线程,一个是jvm的主线程用于执行程序。另一个是jvm的垃圾回收线程用于回收系统资源。
在Java中给我们提供了线程对象及其字段与功能的是Thread。
在Thread类中定义了创建线程对象的方法(构造函数),以及.提供了会被执行的run()方法,要被执行的代码就放在run()方法里。
还定义了开启线程运行的方法(start()).

创建线程有两种方法:
第一种是直接继承Thread类
步骤:
1,继承Thread类。
2,覆盖run方法。将线程要运行的代码定义其中。
3,创建Thread类的子类对象,其实就是在创建线程,调用start方法。
public class test11 {
	public static void main(String[] args){
		Thread t1 = new T1();
		t1.start();
	}
}

class T1 extends Thread{

	public void run() {
		System.out.print("t1线程开启");
	}
	
}
 

第二种是当自定义的类中继承了其它类,这就不能继承其它类,复写run()方法,这时候就让该类实现Runnable接口,复写该接口的run()方法。步骤:

1,定义了实现Runnable接口。
2,覆盖接口的run方法。将多线程要运行的代码存入其中。
3,创建Thread类的对象(创建线程),并将Runnable接口的子类对象作为参数传递给Thread的构造函数。    
4,调用Thread对象的start方法。开启线程。

public class test11 {
	public static void main(String[] args){
		T1 t1 = new T1();
		Thread thread = new Thread(t1);
		thread.start();
	}
}

class T1 implements Runnable{

	public void run() {
		System.out.print("t1线程开启");
	}
	
}

两种方式的特点:
实现方式,因为避免了单继承的局限性,所以创建线程建议使用第二种方式。

多线程具备随机性。因为是由cpu不断的快速切换造成的。这就有可能会产生死锁问题。

死锁的产生有四个条件:
1、 互斥条件:一个资源每次只能被一个进程使用。
2、 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
3、 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
4、 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

而在代码的实现当中就只有两个关键点:
1,多线程代码中有操作共享数据。

2,多条语句操作该共享数据。

当具备两个关键点时,有一个线程对多条操作共享数据的代码执行的一部分。还没有执行完,另一个线程开始参与执行。

就会发生数据错误。

解决方法:

使用同步锁,当一个线程在执行多条操作共享数据代码时,其他线程即使获取了执行权,也不可以参与操作,这就使得这个线程所需的多个资源,在其运行完之前,不被其他线程获取。这也就破坏了上述死锁形成的第二个条件,也就不会造成死锁,但这样使用同步锁一次性就安排好所有的资源,会使得资源的利用率不高,较消耗资源。

Java就对这种解决方式提供了专业的代码。同步

同步的原理:就是将部分操作功能数据的代码进行加锁。
同步的表现形式:1,同步代码块。
2,同步函数。两者有什么不同:

同步代码块使用的锁是任意对象。同步函数使用的锁是this。
注意:对于static的同步函数,使用的锁不是this。是 类名.class 是该类的字节码文件对象,涉及到了单例设计模式的懒汉式。
同步的好处:解决了线程的安全问题。
弊端:较为消耗资源。同步嵌套后,容易死锁。
黑马程序员多线程练习题主要包括两个问题。第一个问题是如何控制四个线程在打印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、付费专栏及课程。

余额充值