多线程技术(线程的创建Thread和Runnble,死锁,线程间通信,join,yield)

 

多线程技术          

1.多线程概述

(1)进程:正在执行中的程序,比如QQ,javac等

(2)线程:进程中的一个独立控制单元,线程控制着进程的执行。一个进程至少有一个线

(3)多线程的好处:可使程序产生同时运行的效果,多线程下载可提高效率。

2.多线程的两种创建方式:

第一种方式:继承Thread类

创建步骤:

(1)定义一个类继承Thread(那么此类也就变成了Thread类,拥有Start方法。

(2)复写Thread类中的run方法(将需要使用多线程运行的代码存在run方法,让线程运行)

(3)调用线程的start方法.

注意:start():开启一个新线程并运行run方法中的代码,

而调用run方法只是对象调用方法,而不会创建新的线程。

 

第二种方式:实现Runnable接口。

创建步骤:

(1) 定义类实现Runnable接口

(2)覆盖Runnable接口中的run方法。(还没有拥有线程)

(3)通过Thread创建线程对象。

(4)将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。

(5)调用Thread类的Start方法开启线程,Runnable接口的run方法即可运行。

3.实现方式和继承方式的区别

(1)继承了一个类不能再继承其他类,java只支持单继承,这样就会出现类继承的局限性。

(2)继承Thread:线程代码存放在Thread类的run方法中,直接就可以调用子类的Start方法即可开启线程。

(3)实现Runnable:线程代码存放在Runnable接口的子类的run方法中,开启线程还需要new Thread();

(4)在定义线程时,建议使用实现方式。

4.线程的状态和获取线程对象以及名称

线程的状态: 1被创建——2运行——3阻塞(临时状态,具备执行资格但没执行)——4冻结———5消亡。

获取都有自己的名称:Thread-编号从0开始

获取对象方法:

static Thread currentThread()获取当前线程对象。getName()获取线程名称。setName()设置线程名称。

5.线程的安全解决

(1)产生安全问题的原因:当多个线程在操作同一个共享数据时,

一个线程还没执行完,另一个线程参与进来,导致共享数据产生了错误。

(2)解决办法:

同步代码块: synchronized(锁对象){需要被同步的代码数据;}

<1>对象如同锁,持有锁的线程才可以在同步中执行。

<2>同步的前提:必须要有两个或两个以上的线程,必须是多个线程使用的同一个锁对象。

同步函数:

非静态同步函数的锁:this

函数需要被对象调用,那么函数都有一个所属对象引用就是this,所以同步函数使用的锁是this.

静态同步函数的锁:class对象

因为静态方法中不可以定义this,所以锁不可能是this。静态进内存时,内存中没有本类对象,

但是一定有该类对应的字节码文件对象,类名.class,该对象的类型是class.

6死锁:同步中钳套同步容易出现死锁现象,应该避免这样现象发生。

class Test implements Runnable
{
	private boolean flag;
	Test(boolean flag)
	{
		this.flag = flag;
	}

	public void run()
	{
		if(flag)
		{
			while(true)
			{
				synchronized(MyLock.locka)
				{
					System.out.println(Thread.currentThread().getName()+"...if locka ");
					synchronized(MyLock.lockb)
					{
						System.out.println(Thread.currentThread().getName()+"..if lockb");					
					}
				}
			}
		}
		else
		{
			while(true)
			{
				synchronized(MyLock.lockb)
				{
					System.out.println(Thread.currentThread().getName()+"..else lockb");
					synchronized(MyLock.locka)
					{
						System.out.println(Thread.currentThread().getName()+".....else locka");
					}
				}
			}
		}
	}
}


class MyLock
{
	static Object locka = new Object();
	static Object lockb = new Object();
}

class  DeadLockTest
{
	public static void main(String[] args) 
	{
		Thread t1 = new Thread(new Test(true));
		Thread t2 = new Thread(new Test(false));
		t1.start();
		t2.start();
	}
}

 

 

 

 

 

 

 

 

 

 

7.线程间通信

 

(1)线程间通信:

 

其实就是多个线程在操作同一个资源,但操作的动作不同。

 

(2)等待唤醒机制:

 

<1>wait(),notify(),notifyAll()都使用在同步中,因为只有同步才具有锁,所以要对持有锁的线程操作。

 

<2>这些用来操作线程的方法为什么定义在Object类中?

 

a.这些方法存在于同步中。

 

b.使用这些方法时必须要标识所属的同步的锁。

 

c.等待和唤醒必须是同一个锁。

 

d.锁可以是任意对象,所以任意对象调用的方法一定定义在Object中。

 

(3)wait(),sleep()的区别:

 

wait():释放资源,释放锁。

 

sleep():释放资源,不释放锁。

 

(3)举例:生产者与消费者

 

<1>对于多个生产者和消费者,为让被唤醒的线程再一次判断标记,故要定义while判断标记。

 

<2>为什么定义notifyAll?

 

因为需要唤醒对方线程,只用notify容易出现只唤醒本方线程的情况,导致程序中的所有

 

线程都等待。

 

<3>JDK1.5提供的多线程升级解决方案。

 

将同步synchronized替换成现实Lock操作。将Object中的wait,notify,notifyAll替换成了

 

condition对象。该对象可以用Lock锁进行获取。

 

8.停止线程:

 

(1)stop方法已经过时。

 

(2)如何停止线程?

 

只有一种,就是让run方法结束,开启多线程运行,运行代码通常是循环结构。只要控制住循环,

 

就可以让run方法结束,也就是线程结束。

 

(3)特殊情况:

 

<1>当线程处于了冻结状态,就不会读到标记,那么线程就不会结束。

 

<2>当没有指定的方式让冻结的线程恢复到运行状态时,这时需要对冻结进行清除,强制让线程恢复

 

到运行状态中来,这样就可以操作标记让线程结束。

 

(4)Thread类提供该方法:interrupt()

 

9.守护线程:

 

setDaemon:

 

public final void setDaemon(boolean on)

 

(1)当正在运行的线程都是守护线程时,JVM退出。

 

(2)该方法必须在启动线程前调用。

 

(3)主线程是前台线程,前台线程一结束,守护线程自动结束。

 

10.join方法:

 

join://抢夺CPU执行权

 

public final void join()

 

throws InterruptedException

 

等待该线程终止

 

(1)当A线程执行到了B线程的join()方法时,A就会等待,等B线程都执行完,A才会执行。

 

(2)join可以用来临时加入线程执行。

 

11.优先级&yield方法

 

setPriority(int newPriority)

 

更改线程的优先级(默认是5)

 

(1) MAX_PRIORITY-->10

 

NORM_PRIORITY--->5

 

MIN_PRIORITY--->1

 

(2)注:在任务管理器的进程中,也可进行优先级设置。

 

yield:临时停止

 

public static void yield()

 

暂停当前正在执行的线程对象,并执行其他线程。yield可稍微减缓线程的运行,

 

使线程达到接近平均运行的效果。

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章