黑马程序员_多线程1

来源:互联网 发布:同花顺自动交易软件 编辑:程序博客网 时间:2024/05/23 12:52

------- android培训、java培训、期待与您交流! ----------


线程:是程序中的执行线程。

Java 虚拟机允许应用程序并发地运行多个执行线程。


一、线程的创建

创建新执行线程有两种方法。

一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例。

例如,计算大于某一规定值的质数的线程可以写成:

class PrimeThread extends Thread {long minPrime;PrimeThread(long minPrime) {this.minPrime = minPrime;} public void run() {// compute primes larger than minPrime . . .}}

然后,下列代码会创建并启动一个线程:

PrimeThread p = new PrimeThread(143);p.start();

创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后可以分配该类的实例,在创建Thread 时作为一个参数来传递并启动。

采用这种风格的同一个例子如下所示: 

class PrimeRun implements Runnable {long minPrime;PrimeRun(long minPrime) {this.minPrime = minPrime;} public void run() {// compute primes larger than minPrime . . .}}

然后,下列代码会创建并启动一个线程:

PrimeRun p = new PrimeRun(143);new Thread(p).start();


那么,线程的创建方式选择哪个更好呢?

答案是实现Runnable接口更好一些


1.因为实现Runnable接口可以避免Java单继承的局限性。

当一个类继承了Thread,就不可以在继承其他类了。

而当一个类实现了Runnable,它一样可以继承其他类。

比如 class Demo extends SuperDemo implements Runnable{}


2.更符合面向对象的设计。

run()方法的作用是用来封装线程要运行的代码。

那么run()方法所属的对象,就是线程任务对象。

Thread类的子类对象即使线程对象,又是线程任务对象。耦合性很强。

有了Runnable接口,可以将线程任务和线程进行解耦,提高了程序的扩展性。


所以建议使用Runnable接口的方式完成线程的创建。


二、多线程的安全问题

多线程安全问题:当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,另一个线程参与进来执行,就会导致共享数据的错误。

解决办法:对多条操作共享数据的语句,只能让一个线程执行。在执行过程中,其他线程不可以参与执行。

Java提供了一种解决方式:同步代码块 synthronized(Object obj) { 需要被被同步的代码 }

Object 如同锁,持有锁的线程可以在同步代码块中执行。没有持有锁的线程即使持有CPU的执行权,也无法执行同步代码。

同步的前提:

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

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

好处:解决了多线程的安全问题。 弊端:线程需要判断锁,较为消耗资源。

如何找安全问题?

1.明确哪些代码是多线程运行代码

2.明确共享数据

3.明确多线程运行代码中哪些语句是操作共享数据的

第二种同步的方式:同步函数  用synchronized修饰函数

在非静态同步函数中,用的锁是this。因为函数需要被对象调用,那么函数都有一个所属对象引用,这个引用就是this。

在静态同步函数中,用的锁是类名.class。静态函数进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象:类名.class,该对象的类型是Class类。


另外,在单例设计模式中有饿汉式和懒汉式,实际开发用饿汉式,但面试常考懒汉式。 

懒汉式特点:实例的延迟加载
问题:多线程访问时会出现安全问题。
用同步代码块或同步函数均可,但有些低效,用双重判断解决效率问题,同步代码块使用的锁为该类所属的字节码文件对象。

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 DeadLock implements Runnable {private boolean flag;DeadLock(boolean flag) {this.flag = flag;}public void run() {for (int i = 0; i < 40; i++) {if(flag) {synchronized(Lock.lock1) {System.out.println("iflock1..."+i);synchronized(Lock.lock2) {System.out.println("iflock2..."+i);}}}else {synchronized(Lock.lock2) {System.out.println("elselock2..."+i);synchronized(Lock.lock1) {System.out.println("elselock1..."+i);}}}}}}class Lock {public static Object lock1 = new Object(); public static Object lock2 = new Object(); }


原创粉丝点击