java多线程

什么是多线程?
多线程就是一个程序中同时执行的多个顺序流(就是一个程序中同时运行多段代码)
如何创建一个线程?
第一种方式:
线程类:这个类中的代码可以作为一个顺序流(线程)单独的运行
特性 : 需要实现Runnable接口

如果一个类实现了Runnable接口,那么这个类中的代码就可以作为一个单独的线程来运行;
我们要想把这个类中的代码作为一个线程来运行:
① 这个类要实现Runnable接口,重写run方法;
② 创建这个类(Runnable)对象;
③ 根据这个Runnable对象创建线程;
④ 启动线程。
实例:
/**
* 当我们这个类实现了Runnable借口,我们这个类就变成了线程类
* 这个类中的代码就可以作为单独的顺序流来执行
* 当我们启动了这个线程后,这个顺序流就从run方法中的第一句代码执行
* run方法就是一个线程入口
*/
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println("<>"+i);
}
}
public static void main(String[] args) {
//根据TextThead线程类创建一个线程,然后启动这个线程
//创建Runnable对象
Runnable r=new TextThread();
//根据这个对象来创建一个线程
Thread t=new Thread(r);
//启动线程:通过Thread中的start()方法启动线程
t.start();

for(int i=0;i<100;i++){
System.out.println("------"+i);
}
}
创建线程的第二种方式:(//重写父类方法:右键--->source-->override/implements method)
① 创建一个类继承Thread—重写run方法,实现Runnable类;
② 创建这个类的对象,这个对象本身就是线程;
③ 通过这个对象调用start方法启动线程,就会以单独的线程的形式执行当前类的run方法。

当我们使用线程对象调用start方法之后,实际上并没有立即开始执行,它指的是让当前线程进去到“可运行状态”--------值得是这个线程可以运行,但是还没有运行
注意:不要直接在程序中调用run()方法!
状态变化:
[img]http://dl.iteye.com/upload/attachment/0074/9927/d140071f-9b0e-3d2b-9ac2-2fbbf1ed4279.jpg[/img]

两种线程创建方式的比较:

使用Runnable接口
可以将CPU,代码和数据分开,形成清晰的模型;
还可以从其他类继承;
保持程序风格的一致性。

直接继承Thread类
不能再从其他类继承;
编写简单,可以直接操纵线程,无需使用Thread.currentThread()。
[img]http://dl.iteye.com/upload/attachment/0074/9929/4362d7d9-aa4b-3cc1-8a91-a68ca5ee7527.jpg[/img]

线程结束的方式:
运行结束-----抛出异常结束---手动结束
线程到达其 run() 方法的末尾;抛出一个未捕获到的 Exception 或 Error;

方法 说明
start() 新建的线程进入Runnable状态
run() 线程进入Running 状态
wait() 线程进入等待状态,等待被notify,这是一个对象方法,而不是线程方法
notify()/
notifyAll() 唤醒其他的线程,这是一个对象方法,而不是线程方法
yield() 线程放弃执行,使其他优先级不低于此线程的线程有机会运行,它是一个静态方法
getPriority()/setPriority() 获得/设置线程优先级
sleep() 线程睡眠指定的一段时间
join() 调用这个方法的主线程,会等待加入的子线程完成
线程可以分为‘守护线程’和‘用户线程’:
//用户线程:当用户线程执行结束后,无论其他的线程是否执行结束,这个用户线程都会停止
//守护线程:为用户线程提高服务,直到最后一个用户线程执行结束后才结束守护线程

//作为一个用户线程,无论需要花多长执行时间,只要不出现异常,最后都要把代码执行结束
//作为一个守护线程,无论有多少代码,无论代码是否执行结束,只要用户线程都结束了,守护线程也会停止执行
//main方法是默认的守护线程

//我们直接创建的线程默认是‘用户线程’
//我们可以通过setDeamon(true)方法将一个用户线程设置为守护线程
//我们可以通过setDeamon(false)方法将一个守护线程设置为用户线程
//我们还可以通过isDeamon()方法判断某个线程是否是守护线程

线程的名字:
我们创建的每一个线程都是有线程名的,默认线程名:Thread-n
我们也可以为创建的线程命名
[img]http://dl.iteye.com/upload/attachment/0074/9931/0676cfc5-b997-3a0d-9486-79aa75cc3a91.jpg[/img]

线程的优先级:
//线程的优先级:分为1-10 共十个级别
//数值越大,优先级越高
//我们在没有设置优先级的情况下,默认级别为5
//线程优先级高,并不代表优先级低的就不执行,只让优先级高的执行;
//在单位时间内,优先级高的线程能够有更多的执行机会,优先级低的也有机会执行,只是机会更少

//获取当前线程的优先级---getPriority()方法
//System.out.println(t1.getPriority());

//setPriority()设置当前线程优先级
t1.setPriority(1);
t2.setPriority(10);

Join方法:
Thread API 包含了等待另一个线程完成的方法:join() 方法。当调用 Thread.join() 时,调用线程将阻塞,直到被join方法加入的目标线程完成为止。
Thread.join() 通常由使用线程的程序调用,以将大问题划分成许多小问题,每个小问题分配一个线程。当所有的小问题都得到处理后,再调用主线程来进一步操作。
try {
//创建一个线程并启动
Myjoin1 j1=new Myjoin1();
Thread j2=new Thread(new Myjoin2());
j1.start();
j2.start();

//只保证当前线程不与j1线程竞争资源,也就是说只要j1线程执行结束了
//无论其他的线程执行的怎么样,main方法都会恢复执行,再与其他线程参与竞争资源
j1.join();

for (int i = 0; i < 100; i++) {
System.out.println("main"+i);
if(i==10){
//如果在main线程中调用了j.join()方法
//指的是让main线程处于休眠状态,直到被join的线程j执行结束后才恢复执行
j1.join();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}


线程sleep()方法:延时当前线程时间,当前线程让出资源并且不参与竞争,当时间到了就结束休眠参与资源竞争!
public static void main(String[] args) {
try {
MyThread05 t5 = new MyThread05();
t5.start();

for (int i = 1; i <= 100; i++) {
System.out.println(i);
if(i==10){
//让当前线程休眠1ms,在休眠的这1ms之内,当前线程让出资源并且不参与竞争
//时间到了就结束休眠参与资源竞争
Thread.sleep(1);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
线程的wait()方法:
如果某个线程调用了wait方法,那么这个线程就会处于休眠状态,直到有其他线程调用notify或者notifyAll方法适合才能唤醒此线程,此线程才能接着执行!

多线程的数据共享:
当多个线程同时访问同一个对象(数据)时候,因为线程执行顺序的不确性,有可能倒置数据的错误
解决方法:当某一个线程在访问公用对象(数据)的时候,对这个数据进行锁定,锁定之后的其他线程如果想要访问这个数据,就必须等待该线程释放这数据
在某些线程执行过程中,可能有多个步骤必须连接执行(文件拷贝/银行取款问题)

Synchronized关键字:对某一个线程进行锁定,锁定之后其他线程就不能访问资源数据了!

互诉锁:
在Java语言中,引入了对象互斥锁(mutual exclusive lock,也简称为对象锁)的概念,来保证共享数据操作的完整性:
每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
关键字synchronized 来与对象的互斥锁联系。当某个对象用synchronized修饰时,表明该对象在任一时刻只能由一个线程访问。

对多个线程同时对某一个方法(资源)同时调用时候,synchronized关键字:
修饰方法名/锁定方法的调用者(对象)
①此时表示只能被一个线程访问,对其他正在运行的线程如果有访问这个数据方法时候就处于等待状态,直到当前线程释放对象的锁(代码执行结束)才能访问;对其他没有访问这个方法数据的线程则不受影响。
②如果多个方法都添加了关键字,并且都使用到相同的当前类对象(通过相同的对象调用不同的方法),这多个方法就不能同时执行,如果调用的第一个方法线程开始执行了,其他的方法线程就只能处于等待状态,当这个方法执行结束后,其他的方法才能竞争执行权
*同一个对象就是一个人只能做一件事。
*不同对象就是两个人各做各得事情。
在Java中的两种使用synchronized的方式:
放在方法前面,这样,调用该方法的线程均将获得对象的锁。
放在代码块前面,它也有两种形式:
synchronized (this){… …}或synchronized {… …}:代码块中的代码将获得当前对象引用的锁
synchronized(otherObj){… …}:代码块中的代码将获得指定对象引用的锁

释放锁:
如果一个线程一直占用一个对象的锁,则其他的线程将永远无法访问该对象,因此,需要在适当的时候,将对象锁归还。
当线程执行到synchronized()块结束时,释放对象锁。
当在synchronized()块中遇到break, return或抛出exception,则自动释放对象锁。
当一个线程调用wait()方法时,它放弃拥有的对象锁并进入等待队列。

死锁:
是指两个线程,都相互等待对方释放lock
是不可测知或避开的
应采取措施避免死锁的出现
常用方法:notify()Wait()notifyAll()Thread.interrupt()
Object 类定义了 wait()、notify() 和 notifyAll() 方法。可以让线程相互通知事件的发生。要执行这些方法,必须拥有相关对象的锁。
wait() 会让调用线程休眠,直到用 Thread.interrupt() 中断它、过了指定的时间、或者另一个线程用 notify() 或 notifyAll() 唤醒它。
当对某个对象调用 notify() 时,如果有任何线程正在通过 wait() 等待该对象,那么就会唤醒其中一个线程。当对某个对象调用 notifyAll() 时,会唤醒所有正在等待该对象的线程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值