------- android培训、java培训、期待与您交流!---------
多线程技术
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可稍微减缓线程的运行,
使线程达到接近平均运行的效果。